Открыть сервис

Фантомное чтение

Фантомное чтение — это феномен в области баз данных, представляющий собой один из трёх стандартных типов аномалий, возникающих при параллельном выполнении транзакций (наряду с «грязным чтением» и «неповторяющимся чтением»). Фантомное чтение заключается в том, что в рамках одной транзакции при повторном выполнении одного и того же запроса на выборку данных (например, по условию) возвращается разное количество строк. При этом ранее отсутствовавшие строки (так называемые «фантомные» записи) могут быть добавлены или, напротив, исчезнуть в результате завершения другой конкурирующей транзакции, работающей с тем же диапазоном данных. Данная аномалия нарушает свойство изолированности транзакций (I — Isolation) в модели ACID.

Определение и сущность явления

Фантомное чтение возникает, когда транзакция читает данные, удовлетворяющие некоторому условию (например, WHERE price > 1000), а затем, после того как другая транзакция вставила, удалила или изменила записи в том же диапазоне, первая транзакция при повторном выполнении запроса получает набор строк, отличный от первоначального. В отличие от неповторяющегося чтения, где изменяется содержимое уже существующих строк, при фантомном чтении изменяется сам состав записей (появляются или исчезают целые строки).

Основные признаки

Отличие от других аномалий

Для более точного понимания фантомного чтения необходимо различать его с другими аномалиями параллельного доступа:

Уровни изоляции транзакций в SQL

Стандарт SQL-92 определяет четыре уровня изоляции транзакций, которые предотвращают различные степени аномалий. Отношение к фантомному чтению выглядит следующим образом:

Уровень изоляцииГрязное чтениеНеповторяющееся чтениеФантомное чтение
READ UNCOMMITTEDВозможноВозможноВозможно
READ COMMITTEDНевозможноВозможноВозможно
REPEATABLE READНевозможноНевозможноВозможно (в большинстве СУБД)
SERIALIZABLEНевозможноНевозможноНевозможно

Особенности на уровне REPEATABLE READ

Хотя стандарт SQL предполагает, что на уровне REPEATABLE READ фантомное чтение возможно, многие современные СУБД (например, PostgreSQL, MySQL с InnoDB) на этом уровне предотвращают данную аномалию. Это достигается за счёт использования механизмов многоверсионности (MVCC) и блокировок диапазона (gap locks/next-key locks). В таких системах REPEATABLE READ эквивалентен SERIALIZABLE в отношении фантомов, но без полной блокировки табличных операций.

Пример ситуации

Рассмотрим две параллельные транзакции в банковской системе для иллюстрации фантомного чтения:

  1. Транзакция A начинает работу и выполняет запрос: SELECT COUNT(*) FROM accounts WHERE balance > 10000; — результат: 5 счетов.
  2. Транзакция B в это же время вставляет новый счёт с балансом 15000 и фиксирует изменения (COMMIT).
  3. Транзакция A повторяет тот же запрос: SELECT COUNT(*) FROM accounts WHERE balance > 10000; — результат: 6 счетов.

Причина появления «фантомной» строки (нового счёта) — транзакция A не наложила блокировку на диапазон balance > 10000, поэтому вставка от транзакции B стала видимой.

Причины возникновения

Фантомное чтение возникает из-за отсутствия или недостаточности блокировок на уровне диапазона данных. Базовые механизмы:

Способы предотвращения

1. Уровень изоляции SERIALIZABLE

Наиболее надёжный, но и самый ресурсоёмкий способ. Система гарантирует, что транзакции выполняются так, как если бы они шли последовательно. Для этого часто применяются блокировки диапазона (gap locks) или полные блокировки таблицы.

2. Блокировки диапазона (Gap Locks, Next-Key Locks)

Некоторые СУБД, например MySQL с движком InnoDB, реализуют так называемые next-key locks, которые блокируют не только существующие строки, но и пространство между ними. Это предотвращает вставку новых записей, попадающих в диапазон, на который наложена блокировка.

3. Многоверсионность с моментальными снимками (Snapshot Isolation)

Используется, например, в PostgreSQL и Oracle. Транзакция получает «снимок» базы данных на момент своего начала. Все последующие изменения от других транзакций не видны, даже если они зафиксированы. Однако в некоторых реализациях (в зависимости от механизма) фантомное чтение может сохраняться для запросов, использующих недетерминированные функции или условия, зависящие от времени.

Последствия и влияние на бизнес-логику

Фантомное чтение может иметь серьёзные последствия для целостности данных и бизнес-процессов:

Реализации в конкретных СУБД

PostgreSQL

MySQL (InnoDB)

Microsoft SQL Server

Oracle

Возможные пути решения на уровне приложения

Если база данных не поддерживает SERIALIZABLE или REPEATABLE READ с защитой от фантомов, разработчики могут применить следующие тактики:

Критика и ограничения

Хотя фантомное чтение считается аномалией, некоторые исследователи отмечают, что для многих прикладных задач его предотвращение излишне. Системы, работающие с большими объёмами данных и высокими нагрузками, часто сознательно жертвуют строгой изолированностью ради производительности. Кроме того, реализация защиты от фантомов (особенно через блокировки диапазона) может приводить к существенным снижениям пропускной способности СУБД.

Альтернативные модели согласованности (например, «ленивая репликация» (lazy replication) или «событийная согласованность» (eventual consistency)) часто допускают фантомное чтение как допустимое для некритичных операций.

Источники

  1. Кодд Э. Ф. «Реляционная модель данных для больших банков данных» — 1970.
  2. Стандарт ISO/IEC 9075-1:2016 «Информационные технологии — Языки баз данных — SQL — Часть 1: Структура».
  3. Грей Дж., Рейтер А. «Транзакционные системы: Управление параллелизмом и восстановлением» — 1993.
  4. Бернштейн Ф., Гудман Н. «Управление параллелизмом в распределённых базах данных» — ACM Computing Surveys, 1981.
  5. Постгрес Документация «Уровни изоляции транзакций» — PostgreSQL Global Development Group.
  6. InnoDB Locking — MySQL 8.0 Reference Manual.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →