Что такое аномалия «фантомное чтение» (Phantom Read)?

Ответ

Фантомное чтение (Phantom Read) — это аномалия конкурентного доступа, при которой одна транзакция в ходе своего выполнения несколько раз выполняет один и тот же запрос с одним и тем же условием выборки (WHERE) и получает разное количество строк.

Это происходит, когда другая параллельная транзакция успевает добавить или удалить строки, которые подпадают под условие выборки первой транзакции, и зафиксировать свои изменения (COMMIT). Новые, "появившиеся из ниоткуда" строки и называются "фантомами".

Отличие от неповторяющегося чтения (Non-Repeatable Read)

Важно не путать эти две аномалии:

  • Неповторяющееся чтение: Изменяются данные в уже существующих строках. (Например, SELECT ... WHERE id = 5 сначала возвращает status = 'pending', а потом status = 'completed').
  • Фантомное чтение: Появляются новые строки или исчезают существующие. (Например, SELECT COUNT(*) WHERE status = 'pending' сначала возвращает 10, а потом 11).

Пример сценария


  1. Транзакция 1 подсчитывает количество активных задач в проекте 'X':

    SELECT COUNT(*) FROM tasks WHERE project_id = 'X' AND status = 'active'; — получает результат 5.



  2. Транзакция 2 добавляет новую активную задачу в тот же проект и фиксирует изменения:

    INSERT INTO tasks (project_id, status) VALUES ('X', 'active');

    COMMIT;



  3. Транзакция 1 в рамках своей логики выполняет тот же самый запрос еще раз:

    SELECT COUNT(*) FROM tasks WHERE project_id = 'X' AND status = 'active'; — и внезапно получает результат 6. Эта новая шестая строка и есть "фантом".


Как предотвратить

  • Уровень изоляции Repeatable Read: В некоторых СУБД (например, PostgreSQL) этот уровень уже предотвращает фантомное чтение. Однако в других (например, MySQL InnoDB) он защищает только от неповторяющегося чтения, но не от фантомов.
  • Уровень изоляции Serializable: Это самый надежный способ полностью исключить фантомные чтения, так как он гарантирует, что транзакции будут выполняться так, как если бы они шли одна за другой.