В чем разница между неповторяющимся чтением и фантомным чтением?


155

В чем разница между неповторяющимся чтением и фантомным чтением?

Я прочитал статью « Изоляция (системы баз данных)» из Википедии , но у меня есть несколько сомнений. Что будет в следующем примере: неповторяющееся чтение и фантомное чтение ?

Транзакция А
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
ВЫВОД:
1----MIKE------29019892---------5000
Транзакция Б
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
Транзакция А
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1

Другое сомнение заключается в том, какой уровень изоляции следует использовать в приведенном выше примере? И почему?


Ответы:


166

Из Википедии (где есть отличные и подробные примеры):

Неповторяемое чтение происходит, когда в ходе транзакции строка извлекается дважды, а значения в строке различаются между операциями чтения.

и

Фантомное чтение происходит, когда в ходе транзакции выполняются два идентичных запроса, а набор строк, возвращаемых вторым запросом, отличается от первого.

Простые примеры:

  • Пользователь A выполняет один и тот же запрос дважды.
  • В промежутке пользователь B запускает транзакцию и фиксирует.
  • Неповторяемое чтение: строка, к которой обратился пользователь A, имеет другое значение во второй раз.
  • Фантомное чтение: все строки в запросе имеют одинаковое значение до и после, но выбираются разные строки (потому что B удалил или вставил некоторые). Пример: select sum(x) from table;вернет другой результат, даже если ни одна из затронутых строк не была обновлена, если строки были добавлены или удалены.

В приведенном выше примере, какой уровень изоляции будет использоваться?

Какой уровень изоляции вам нужен, зависит от вашего приложения. «Лучший» уровень изоляции обходится дорого (например, снижение параллелизма).

В вашем примере у вас не будет фантомного чтения, потому что вы выбираете только из одной строки (идентифицируемой первичным ключом). У вас могут быть неповторяющиеся чтения, поэтому, если это проблема, вы можете захотеть иметь уровень изоляции, который предотвращает это. В Oracle транзакция A также может выдавать SELECT FOR UPDATE, тогда транзакция B не может изменить строку до тех пор, пока A не будет завершена.


6
Я не очень понимаю логику такого синтаксиса ... Не повторяемое чтение происходит, когда чтение повторяется (и получается другое значение) ??! ...
serhio

14
@serhio «неповторяемый» относится к тому факту, что вы можете прочитать значение один раз и получить x в качестве результата, а затем снова прочитать и получить y в качестве результата, так что вы не можете повторить (неповторяемые) одинаковые результаты из двух отдельные запросы одной и той же строки, потому что это значение строки было обновлено между чтениями.
BateTech

@Thilo Какой-нибудь реальный пример использования, где repeatable-read может создать проблемы и где это необходимо?
user104309

Что если PK будет изменен в другой транзакции? Может ли это привести к фантомному чтению? (Странная вещь, которую нужно сделать в большинстве случаев, но не невозможно.)
jpmc26

1
Оба звучат одинаково для меня
sn.anurag

127

Простой способ мне нравится думать об этом:

И неповторяющиеся, и фантомные чтения имеют отношение к операциям модификации данных из другой транзакции, которые были зафиксированы после начала вашей транзакции, а затем прочитаны вашей транзакцией.

Неповторяемые чтения - это когда ваша транзакция читает подтвержденные ОБНОВЛЕНИЯ из другой транзакции. Теперь та же строка имеет значения, отличные от тех, которые были в начале вашей транзакции.

Phantom читает похожи , но при чтении совершенных INSERTS и / или удалений из другой транзакции. Есть новые строки или строки, которые исчезли с момента начала транзакции.

Грязное чтение аналогично неповторяющемуся и фантомному чтению, но относится к чтению НЕКОММИТИРОВАННЫХ данных и происходит, когда читается UPDATE, INSERT или DELETE из другой транзакции, а другая транзакция еще не зафиксировала данные. Это чтение данных «в процессе», которые могут быть неполными и никогда не быть зафиксированными.


4
Это связано с уровнями изоляции транзакций и параллелизмом. Используя уровень изоляции по умолчанию, вы не получите грязное чтение, и в большинстве случаев вы хотите избежать грязного чтения. Существуют уровни изоляции или подсказки запросов, которые допускают грязное чтение, что в некоторых случаях является приемлемым компромиссом для достижения более высокого уровня параллелизма или необходимо из-за пограничного случая, такого как устранение неполадок в текущей транзакции из другого соединения. Хорошо, что идея грязного чтения не проходит для вас «тест на запах», потому что, как правило, их следует избегать, но у них есть цель.
BateTech

1
@PHPAvenger в данном случае используется для уровня изоляции READ UNCOMMITTED: всегда есть возможность зайти в тупик между запросом на выборку и обновлением (объяснение здесь ). Если запрос на выбор слишком сложен для создания покрывающего индекса, во избежание взаимных блокировок вы захотите использовать уровень изоляции READ UNCOMMITED с риском возникновения грязных чтений, но как часто вы выполняете откат транзакций, чтобы беспокоиться об этих грязных чтениях, не быть постоянным ?!
petrica.martinescu

1
@ petrica.martinescu проблемы, вызванные грязным чтением, не связаны с тем, отменен ли откат транзакции. Грязное чтение может привести к очень неточным результатам в зависимости от того, как были изменены данные в ожидающих транзакциях. Представьте себе транзакцию, которая выполняет серию из нескольких удалений, обновлений и / или вставок. Если вы прочитали данные в середине этой транзакции, используя «read uncommitted», они будут неполными. Уровень изоляции моментальных снимков (в SQL Server) - гораздо лучшая альтернатива чтению незафиксированных. Допустимый вариант использования для чтения незафиксированного уровня изоляции в производственной системе - редкий IMO.
BateTech

2
@DiponRoy отличный вопрос. Блокировка, реализованная при использовании изоляции с повторяющимся чтением (RR), должна предотвращать удаление в выбранных строках. За последние годы я видел разные определения уровней 2 iso, в основном говоря, фантом - это изменение в возвращаемых строках collection / #, а RR - это та же самая изменяемая строка. Я только что проверил обновленную документацию MS SQL, в которой говорится, что удаление может привести к отсутствию RR ( docs.microsoft.com/en-us/sql/odbc/reference/develop-app/… ), поэтому я думаю, что было бы безопасно группировать удаления в категория RR тоже
BateTech

2
@anir да вставки и удаления включены в грязные чтения. Пример: начать транзакцию, вставить 2 из 100 строк счета-фактуры в соединение a, теперь соединение b считывает эти 2 строки перед фиксацией trx и перед добавлением других 98 строк, и поэтому не включает всю информацию для счета-фактуры. Это было бы грязное чтение, включающее вставку.
BateTech

28

Как объясняется в этой статье , аномалия неповторяемого чтения выглядит следующим образом:

введите описание изображения здесь

  1. Алиса и Боб запускают две транзакции базы данных.
  2. Боб читает запись записи, а значение столбца заголовка - Транзакции.
  3. Алиса изменяет заголовок данной записи записи на значение ACID.
  4. Алиса совершает свою транзакцию базы данных.
  5. Если Боб перечитывает запись записи, он увидит другую версию этой строки таблицы.

В этой статье о фантомном чтении вы можете увидеть, что эта аномалия может произойти следующим образом:

введите описание изображения здесь

  1. Алиса и Боб запускают две транзакции базы данных.
  2. Боб читает все записи post_comment, связанные со строкой сообщения со значением идентификатора 1.
  3. Алиса добавляет новую запись post_comment, которая связана со строкой записи, имеющей значение идентификатора 1.
  4. Алиса совершает свою транзакцию базы данных.
  5. Если Боб перечитывает записи post_comment со значением столбца post_id, равным 1, он будет наблюдать другую версию этого набора результатов.

Таким образом, хотя неповторяемое чтение применяется к одной строке, фантомное чтение относится к диапазону записей, которые удовлетворяют заданным критериям фильтрации запросов.


3
превосходная визуализация @Vlad
dextermini

23

Читать явления

  • Грязное чтение : чтение НЕКОММЕНТОВанных данных из другой транзакции
  • Неповторяемые чтения : чтение данных COMMITTED изUPDATEзапроса из другой транзакции
  • Фантомное чтение : чтение данных COMMITTED изINSERTилиDELETEзапроса из другой транзакции

Примечание : операторы DELETE из другой транзакции также имеют очень низкую вероятность вызвать неповторяющиеся чтения в некоторых случаях. Это происходит, когда оператор DELETE, к сожалению, удаляет ту же строку, к которой обращалась ваша текущая транзакция. Но это редкий случай, и гораздо менее вероятно, что он произойдет в базе данных, содержащей миллионы строк в каждой таблице. Таблицы, содержащие данные транзакций, обычно имеют большой объем данных в любой производственной среде.

Также мы можем заметить, что ОБНОВЛЕНИЯ могут быть более частой работой в большинстве случаев использования, а не фактической ВСТАВКОЙ или УДАЛЕНИЯМИ (в таких случаях остается опасность только неповторяющихся чтений - фантомные чтения в этих случаях невозможны). Вот почему ОБНОВЛЕНИЯ обрабатываются иначе, чем INSERT-DELETE, и результирующая аномалия также называется по-разному.

Существует также дополнительная стоимость обработки, связанная с обработкой для INSERT-DELETE, а не просто с обработкой ОБНОВЛЕНИЙ.


Преимущества разных уровней изоляции

  • READ_UNCOMMITTED ничего не мешает. Это нулевой уровень изоляции
  • READ_COMMITTED предотвращает только один, то есть Грязное чтение
  • REPEATABLE_READ предотвращает две аномалии: грязное чтение и неповторяемое чтение
  • SERIALIZABLE предотвращает все три аномалии: грязные чтения, неповторяющиеся чтения и фантомные чтения

Тогда почему бы просто не установить транзакцию SERIALIZABLE в любое время? Что ж, ответ на поставленный выше вопрос таков: настройка SERIALIZABLE делает транзакции очень медленными , чего мы опять не хотим.

Фактически потребление времени транзакции происходит в следующем размере:

SERIALIZABLE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED

Поэтому установка READ_UNCOMMITTED является самой быстрой .


Резюме

На самом деле нам нужно проанализировать сценарий использования и определить уровень изоляции, чтобы оптимизировать время транзакции, а также предотвратить большинство аномалий.

Обратите внимание, что базы данных по умолчанию имеют настройку REPEATABLE_READ.


1
ОБНОВЛЕНИЕ или УДАЛЕНИЕ оба могут иметь место для неповторяющихся чтений, или это только ОБНОВЛЕНИЕ?
Дипон Рой

1
ОБНОВЛЕНИЕ или УДАЛЕНИЕ оба могут иметь место для неповторяющихся чтений
niket patel

Фактически мы можем резюмировать, что в среднем случайный оператор DELETE, выполняемый другой транзакцией в той же базе данных, имеет очень низкую вероятность вызывать неповторяющиеся чтения для текущей транзакции. Но тот же оператор удаления имеет 100% -ную вероятность вызвать фантомное чтение для текущей транзакции. С моей точки зрения, мои слова немного ошибочны, если вы принимаете это слово в слово. Но, эй, я специально написал это таким образом, чтобы сделать читателя понятнее.
Субхадип Рэй

+1 за простое и понятное объяснение. Однако я думаю, что большинство баз данных (oracle, mysql) имеют уровень изоляции по умолчанию Read Committed, и, вероятно, postgress использует
defaultable

7

Существует разница в реализации между этими двумя уровнями изоляции.
Для «неповторяемого чтения» необходима блокировка строки.
Для «фантомного чтения» необходима блокировка по объему, даже блокировка по таблице.
Мы можем реализовать эти два уровня, используя протокол двухфазной синхронизации .


Для реализации повторяемого чтения или сериализации нет необходимости использовать блокировку строк.
a_horse_with_no_name

5

В системе с неповторяющимися чтениями результат второго запроса транзакции A будет отражать обновление в транзакции B - он увидит новую сумму.

В системе, которая позволяет фантомное чтение, если Транзакция B вставит новую строку с ID = 1, Транзакция A увидит новую строку при выполнении второго запроса; т.е. фантомное чтение - это особый случай неповторяемого чтения.


Я не думаю, что объяснение фантомного чтения правильное. Вы можете получить фантомное чтение, даже если данные без фиксации никогда не видны. Смотрите пример в Википедии (ссылка в комментариях выше).
Тило

1

Принятый ответ указывает, прежде всего, на то, что так называемое различие между ними на самом деле не имеет никакого значения.

Если «строка извлекается дважды, а значения в строке различаются между операциями чтения», то они не являются одной и той же строкой (не одним и тем же кортежем в правильном выражении RDB), и тогда действительно по определению также имеет место «коллекция строки, возвращаемые вторым запросом, отличаются от первого ".

Что касается вопроса «какой уровень изоляции следует использовать», чем больше ваши данные жизненно важны для кого-то, где-то, тем больше будет случай, когда Serializable - ваш единственный разумный вариант.


0

Я думаю, что есть некоторая разница между неповторяющимся чтением и фантомным чтением.

Неповторяемый означает, что есть транзакция буксировки A и B. Если B может заметить модификацию A, поэтому может произойти грязное чтение, поэтому мы позволяем B замечать модификацию A после фиксации A.

Существует новая проблема: мы позволяем B заметить изменение A после фиксации A, это означает, что A изменяет значение строки, которое содержит B, когда-то B снова прочитает строку, поэтому B получит новое значение, отличное от того, когда мы в первый раз получить, мы называем это Неповторимым, чтобы иметь дело с проблемой, мы позволяем B вспомнить что-то (потому что я еще не знаю, что еще запомнится), когда начнется B.

Давайте подумаем о новом решении, мы можем заметить, что есть и новая проблема, потому что мы позволяем B запомнить что-то, поэтому, что бы ни случилось в A, B не может быть затронуто, но если B хочет вставить некоторые данные в таблицу и B проверьте таблицу, чтобы убедиться, что нет записи, но эти данные были вставлены буквой A, поэтому может произойти какая-то ошибка. Мы называем это фантомом.


0

Неповторяемое чтение - это уровень изоляции, а фантомное чтение (чтение зафиксированного значения другими транзакциями) - это концепция (тип чтения, например, грязное чтение или чтение снимка). Неповторяемый уровень изоляции для чтения позволяет фантомное чтение, но не грязное чтение или чтение снимка.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.