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

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

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

Transaction A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
OUTPUT:
1----MIKE------29019892---------5000
Transaction B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
Transaction A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1

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


person user1357722    schedule 15.06.2012    source источник
comment
en.wikipedia.org/wiki/Isolation_(database_systems)   -  person Pavel Veller    schedule 15.06.2012


Ответы (9)


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

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

и

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

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

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

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

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

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

person Thilo    schedule 15.06.2012
comment
Я действительно не понимаю логику такого синтаксиса ... НЕПОВТОРИМОЕ чтение происходит, когда чтение повторяется (и получено другое значение) ??! ... - person serhio; 15.04.2014
comment
@serhio non-repeatable относится к тому факту, что вы можете прочитать значение один раз и получить x как результат, а затем прочитать снова и получить y как результат, поэтому вы не можете повторять (неповторяемые) те же результаты из двух отдельных запросов той же строки, потому что значение этой строки обновлялось между чтениями. - person BateTech; 09.09.2015
comment
@Thilo Любой реальный пример использования, где повторяющееся чтение может создать проблемы и где это необходимо? - person user104309; 19.08.2017
comment
Что, если PK изменен в другой транзакции? Может ли это привести к фантомному чтению? (В большинстве случаев это странно, но возможно.) - person jpmc26; 13.05.2018
comment
Оба звучат для меня одинаково - person sn.anurag; 23.05.2019
comment
Разница в том, что когда вы делаете count(*) from table и возвращаетесь сначала 42, а затем 43, это НЕ является неповторяющимся чтением, потому что для 42 строк, выбранных вами в первый раз, вы получили те же данные во второй раз. Таким образом, не было строки, извлеченной дважды с разными значениями. Но это все еще фантомное чтение, потому что вы получили дополнительную строку. Таким образом, все значения строк по отдельности одинаковы, но теперь вы выбираете разные строки. @ sn.anurag - person Thilo; 23.05.2019
comment
Так возможно ли, что Неповторяющееся чтение и Фантомное чтение одновременно? - person Spaceship222; 21.04.2021
comment
@ Spaceship222 Да, неповторяющееся чтение и фантомное чтение могут происходить в одном и том же наборе результатов чтения. Он имеет те же нюансы, что описаны другими здесь - одна из ранее увиденных строк имеет другое значение где-то в ней. и есть еще одна строка, которой раньше не было :) Это как будто я прошу PrimaryKey, StudentName в классе. 1-й там (1, Noner). Позже в той же транзакции я прочитал записанных студентов и увидел [(1, Неповторяемый), (2, Фантом)]. Нонер подвергся неповторяемости из-за того, что их имя изменилось. Фантом прошел сквозь стену и, казалось, был там все время. - person David Mann; 29.05.2021

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

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

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

Фантомные чтения аналогичны, но при чтении из зафиксированных INSERTS и / или DELETES из другой транзакции. Появились новые строки или строки, которые исчезли с момента начала транзакции.

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

person BateTech    schedule 17.04.2014
comment
Я поражен (или говорю, что не верю). Грязное чтение: чтение измененных данных (другой транзакцией), которые на самом деле не зафиксированы или могут никогда не быть зафиксированы. Где возможно использовать этот сценарий? (Дело не в том, что я вам не верю - на самом деле я не понял концепцию должным образом) - Пожалуйста, не возражайте (вы можете понять разочарование новичка) - person PHP Avenger; 09.09.2015
comment
Это связано с уровнями изоляции транзакций и параллелизмом. Используя уровень изоляции по умолчанию, вы не получите грязных чтений, и в большинстве случаев вы хотите избежать грязных чтений. Существуют уровни изоляции или подсказки для запросов, которые разрешают грязное чтение, что в некоторых случаях является приемлемым компромиссом для достижения более высокого параллелизма или необходимо из-за крайнего случая, например, устранение неполадок в процессе транзакция от другого соединения. Хорошо, что идея грязного чтения не проходит для вас тест на запах, потому что, как правило, их следует избегать, но у них есть цель. - person BateTech; 09.09.2015
comment
Что, если за удалением следует вставка, нельзя ли это использовать для эффективного выполнения обновления? - person Kevin Wheeler; 28.07.2016
comment
@KevinWheeler Я не уверен в релевантности этого сообщения, но удаление с последующей вставкой почти всегда требует гораздо больших затрат по сравнению с обновлением. У вас есть в два раза больше операторов, которые могут быть заблокированы или заблокированы, гораздо больше данных аудита (при отслеживании изменений dml), ​​проверки ограничений FK и т. Д. - person BateTech; 29.07.2016
comment
@PHPAvenger - это вариант использования уровня изоляции READ UNCOMMITTED: всегда есть возможность столкнуться с тупиковой ситуацией между запросом выбора и запросом обновления (объяснено здесь). Если запрос на выбор слишком сложен для создания покрывающего индекса, во избежание взаимоблокировок вы захотите использовать уровень изоляции READ UNCOMMITED с риском возникновения грязных чтений, но как часто вы откатываете транзакции, чтобы беспокоиться об этих грязных чтениях? быть постоянным ?! - person petrica.martinescu; 24.03.2017
comment
@ petrica.martinescu проблемы, вызванные грязным чтением, НЕ связаны только с откатом транзакции. Грязное чтение может возвращать очень неточные результаты в зависимости от того, как были изменены данные в ожидающих транзакциях. Представьте себе транзакцию, которая выполняет серию из нескольких удалений, обновлений и / или вставок. Если вы читаете данные в середине этой транзакции, используя чтение без фиксации, они неполные. Уровень изоляции моментальных снимков (в SQL Server) - гораздо лучшая альтернатива чтению незафиксированных. ИМО, допустимый вариант использования уровня изоляции чтения незафиксированных в производственной системе - редкость. - person BateTech; 03.03.2018
comment
@BateTech UPDATE или DELETE могут иметь место для неповторяющихся чтений или только UPDATE? - person Dipon Roy; 23.04.2018
comment
@DiponRoy отличный вопрос. Блокировка, реализованная при использовании изоляции повторяемого чтения (RR), должна предотвращать удаление выбранных строк. Я видел разные определения двух ISO-уровней на протяжении многих лет, в основном говоря, что фантом - это изменение в возвращаемой коллекции / # строк, а RR - это та же самая строка, которая изменяется. Я только что проверил обновленную документацию MS SQL, в которой говорится, что удаление может вызывать не-RR (docs.microsoft.com/en-us/sql/odbc/reference/develop-app/), поэтому я думаю, что было бы безопасно группа удаляет тоже в категории RR - person BateTech; 26.04.2018
comment
Вы сказали: Грязное чтение похоже на неповторяющееся и фантомное чтение, но связано с чтением НЕПРЕРЫВНЫХ данных и происходит, когда считывается UPDATE, INSERT или DELETE из другой транзакции, а другая транзакция еще НЕ зафиксировала данные. Вы уверены, что UPDATE, INSERT или DELETE включены в грязную запись? Я считаю, что это должно быть просто ОБНОВЛЕНИЕ. - person anir; 24.03.2019
comment
@anir да, вставки и удаления включены в грязное чтение. Пример: начать транзакцию, вставить 2 из 100 строк счета-фактуры на соединение a, теперь соединение b считывает эти 2 строки до фиксации trx и до добавления других 98 строк, поэтому не включает всю информацию для счета-фактуры. Это было бы грязное чтение, включающее вставку. - person BateTech; 24.03.2019
comment
Раньше я сомневался, может ли это быть просто UPDATE или все INSERT, UPDATE и DELETE в случае грязного чтения. Однако теперь я считаю, что это может быть все, как сказано в определении ... изменено незафиксированной транзакцией. Итак, чтение любого эффекта из-за незафиксированной транзакции может привести к грязному чтению, и этот эффект может быть вызван любым из INSERT, UPDATE и DELETE, (Q1), верно? Теперь у меня новый вопрос: нужно ли для этого задействовать отдельный элемент данных / строку или их набор? Опять же, я считаю, что он может все, если следует за эффектом чтения определения, вызванным незафиксированной передачей. (Q2) Верно? - person anir; 24.03.2019
comment
[.. продолжение предыдущего комментария] с указанием двух определений для справки: (1) (Из wiki) Грязное чтение (также известное как незафиксированная зависимость) происходит, когда транзакции разрешено читать данные из строки, которая была изменена другой запущенной транзакцией и еще не зафиксирована. (2) (из книги). Транзакция читает значения, записанные другой транзакцией, которая еще не зафиксирована. Теперь вы можете ответить на мои вопросы из предыдущего комментария? - person anir; 24.03.2019
comment
@anir Q1 влияние на другие транзакции зависит от используемой области транзакции и уровня изоляции. Q2: да, он может включать в себя один элемент данных, строку или набор строк, а также может включать индексы. - person BateTech; 24.03.2019

Аномалия Неповторяющееся чтение выглядит следующим образом:

  Неповторяющееся чтение

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

Аномалия фантомного чтения может произойти следующим образом:

Призрачное чтение

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

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

person Vlad Mihalcea    schedule 01.07.2018

Чтение явлений

  • Грязное чтение: НЕОБХОДИМО чтение данных из другой транзакции.
  • Неповторяющиеся чтения: чтение COMMITTED данных из UPDATE запроса из другой транзакции.
  • Фантомное чтение: чтение ЗАВЕРШЕННЫХ данных из INSERT или DELETE запроса из другой транзакции.

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

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

Также существует дополнительная стоимость обработки, связанная с обработкой INSERT-DELETE, а не просто с обработкой UPDATES.


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

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

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

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

SERIALIZABLE REPEATABLE_READ READ_COMMITTED READ_UNCOMMITTED

Таким образом, параметр READ_UNCOMMITTED является самым быстрым.


Резюме

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

Обратите внимание, что базы данных по умолчанию могут иметь параметр REPEATABLE_READ. Администраторы и архитекторы могут быть склонны выбирать этот параметр по умолчанию, чтобы продемонстрировать лучшую производительность платформы.

person Subhadeep Ray    schedule 11.09.2017
comment
ОБНОВЛЕНИЕ или УДАЛЕНИЕ могут иметь место для неповторяющихся чтений или только ОБНОВЛЕНИЕ? - person Dipon Roy; 23.04.2018
comment
ОБНОВЛЕНИЕ или УДАЛЕНИЕ могут иметь место для неповторяющихся чтений. - person niket patel; 28.09.2018
comment
Фактически мы можем резюмировать, что в среднем случайный оператор DELETE, выполняемый другой транзакцией в той же базе данных, имеет очень низкую вероятность вызвать неповторяющиеся чтения для текущей транзакции. Но тот же оператор удаления имеет 100% шанс вызвать фантомное чтение для текущей транзакции. С этой точки зрения, мое письмо немного неверно, если верить дословно. Но эй, я намеренно написал это так, чтобы читателю было понятнее. - person Subhadeep Ray; 11.04.2019
comment
+1 за простое и понятное объяснение. Однако я думаю, что большинство баз данных (oracle, mysql) имеют уровень изоляции по умолчанию Read Committed и, вероятно, postgress по умолчанию использует repeatable_read - person akila; 13.11.2019
comment
@akila - вру. ;-) Как я уже упоминал. :-) Я говорю о граничном случае. - person Subhadeep Ray; 27.09.2020
comment
@SubhadeepRay Я столкнулся с ситуацией, когда это поток Transaction 1 -> Read integer from DB Transaction 2 -> Read integer from DB Transaction 1 -> Increment, Write and Commit to DB Transaction 2 -> Increment, Write and Commit to DB Теперь этот поток вызывает пропущенное приращение, потому что обе транзакции читают одно и то же целочисленное значение. Итак, есть ли способ защититься от этого потока, который, похоже, не попадает ни в одну из трех категорий грязного чтения, неповторяемого чтения или фантомного чтения? - person abhaybhatia; 24.04.2021

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

person egraldlo    schedule 18.05.2015
comment
Для реализации повторяемого чтения или сериализации нет необходимости использовать блокировку строк. - person a_horse_with_no_name; 02.08.2017

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

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

person Jeffrey Kemp    schedule 15.06.2012
comment
Я не думаю, что объяснение фантомного чтения правильное. Вы можете получить фантомное чтение, даже если данные без фиксации никогда не отображаются. См. Пример в Википедии (ссылка на него приведена в комментариях выше). - person Thilo; 15.06.2012

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

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

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

person Erwin Smout    schedule 02.08.2017

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

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

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

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

person Han R    schedule 22.01.2018

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

person sn.anurag    schedule 23.05.2019