Яка різниця між Неповторним читанням та Прочитаним фантом?


154

Яка різниця між не повторюваним читанням та фантомним читанням?

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

Транзакція A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1
ВИХІД:
1----MIKE------29019892---------5000
Транзакція B
UPDATE USERS SET amount=amount+5000 where ID=1 AND accountno=29019892;
COMMIT;
Транзакція A
SELECT ID, USERNAME, accountno, amount FROM USERS WHERE ID=1

В іншому прикладі ще сумнівається, який рівень ізоляції слід використовувати? І чому?


Відповіді:


165

З Вікіпедії (яка має чудові та докладні приклади для цього):

Читання, яке не повторюється, виникає, коли під час транзакції рядок вилучається двічі, а значення в рядку різняться між показаннями.

і

Фантомне зчитування відбувається, коли під час транзакції виконуються два однакові запити, а колекція рядків, повернута другим запитом, відрізняється від першого.

Прості приклади:

  • Користувач A виконує один і той же запит двічі.
  • Між тим, користувач B виконує транзакцію та здійснює зйомку.
  • Читання, яке не повторюється: Рядок, який запитав користувач A, має другий значення вдруге.
  • Phantom read: Усі рядки запиту мають однакове значення до і після, але вибираються різні рядки (оскільки B видалив або вставив деякі). Приклад: select sum(x) from table;поверне інший результат, навіть якщо жодна із порушених рядків не була оновлена, якщо рядки були додані або видалені.

У наведеному вище прикладі, який рівень ізоляції використовувати?

Який рівень ізоляції вам потрібен, залежить від вашої заявки. Існує висока вартість до "кращого" рівня ізоляції (наприклад, зменшення одночасності).

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


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

14
@serhio "не повторюваний" посилається на те, що ви можете прочитати значення один раз і отримати х як результат, а потім прочитати ще раз і отримати y як результат, тому ви не можете повторити (не повторювані) однакові результати з двох окремі запити того ж рядка, оскільки це значення рядка було оновлено між читаннями.
BateTech

@Thilo Будь-який приклад із реального використання, де повторне читання може створювати проблеми і де це необхідно?
користувач104309

Що робити, якщо ПК змінено в іншій транзакції? Чи може це призвести до фантомного читання? (Дивна річ зробити в більшості випадків, але не неможливо.)
jpmc26

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

125

Простий спосіб, який я люблю думати про це:

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

Неповторювані читання - це коли ваша транзакція зчитує скоєні ОНОВЛЕННЯ з іншої транзакції. Тепер той самий рядок має інші значення, ніж коли він починався.

Фантомні зчитування схожі, але при зчитуванні із скоєних ВСТАВКИ та / або ВИДАЛЕНО з іншої транзакції. З'являються нові рядки або рядки, які зникли з моменту початку транзакції.

Брудні читання схожі на неповторювані та фантомні зчитування, але стосуються читання НЕЗАКОМЕНДОВАНИХ даних і виникають, коли читається ОНОВЛЕННЯ, ВСТАВКА або ВИДАЛЕННЯ з іншої транзакції, а інша транзакція ще НЕ здійснила дані. Це зчитування даних "незавершеного виробництва", які можуть бути не завершеними і ніколи не можуть бути вчинені.


4
Це пов'язано з рівнем ізоляції транзакцій та одночасністю. Використовуючи рівень ізоляції за замовчуванням, ви не забрудниться читанням, і в більшості випадків ви хочете уникнути забруднень. Існують рівні ізоляції або підказки для запитів, які дозволять забруднити читання, що в деяких випадках є прийнятною компромісною метою для досягнення вищої одночасності або необхідною через крайній випадок, наприклад, усунення несправностей у здійсненій транзакції з іншого з'єднання. Добре, що ідея брудного читання не проходить для вас "тесту на запах", як правило, їх слід уникати, але вони мають мету.
BateTech

1
@PHPAvenger - це випадок використання для рівня ЧИТАЙТЕ НЕЗАБАВЛЕННЯ ізоляції: завжди є можливість виявити тупик між запитом вибору та оновлення (пояснено тут ). Якщо запит вибору є надто складним, щоб створити індекс покриття, щоб уникнути тупикових ситуацій, вам потрібно використовувати рівень ЧИТАЙТЕ НЕЗАБАВЛЕНО з ізоляцією ризику зіткнутися з брудними зчитуваннями, але як часто ви робите відкат, щоб турбуватися про те, що вони не читають бути постійним ?!
petrica.martinescu

1
@ petrica.martinescu проблеми, спричинені брудними читаннями, НЕ стосуються лише того, повертається чи ні транзакція. Брудні читання можуть повернути дуже неточні результати залежно від того, як були змінені дані в очікувані транзакції. Уявіть транзакцію, яка виконує серію з декількох видалень, оновлень та / або вставок. Якщо ви читаєте дані в середині транзакції, використовуючи "читання не передано", вони є неповними. Рівень ізоляції знімків (на SQL Server) є набагато кращою альтернативою для читання без відправ. Дійсний випадок використання для прочитаного невдалого рівня ізоляції у виробничій системі є рідкісним ІМО.
BateTech

2
@DiponRoy чудове запитання. Блокування, здійснене, якщо використовується повторювана ізоляція зчитування (RR), повинна запобігати появі видалень у вибраних рядках. Протягом багатьох років я бачив різні визначення рівнів 2 iso, головним чином кажучи, що фантом - це зміна повернутої колекції / # рядків, а 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. Якщо Боб перечитає запис запису, він буде дотримуватися іншої версії цього ряду таблиці.

У цій статті про Phantom Read можна побачити, що ця аномалія може статися так:

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

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

Отже, хоча Неповторне читання застосовується до одного рядка, Phantom Read - це діапазон записів, які відповідають заданим критеріям фільтрації запитів.


3
чудова візуалізація @Vlad
dextermini

23

Прочитайте явища

  • Брудне читання : читайте незабруднені дані з іншої транзакції
  • Читання, яке не повторюється : читайте ЗАРІБНІ дані зUPDATEзапиту з іншої транзакції
  • Phantom читає : читайте COMMITTED дані ззапитуINSERTабоDELETEзапиту з іншої транзакції

Примітка . УВІДКЛЮЧИТИ висловлювання з іншої транзакції, також є дуже низька ймовірність спричинити повторне читання у певних випадках. Це трапляється, коли оператор DELETE, на жаль, видаляє той самий рядок, який запитувала ваша поточна транзакція. Але це рідкісний випадок, і набагато навряд чи це трапиться в базі даних, яка має мільйони рядків у кожній таблиці. Таблиці, що містять дані транзакцій, зазвичай мають великий об'єм даних у будь-якому виробничому середовищі.

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

Також є додаткові витрати на обробку, пов’язані з обробкою для INSERT-DELETE, а не просто обробкою UPDATES.


Переваги різних рівнів ізоляції

  • READ_UNCOMMITTED нічого не перешкоджає. Це нульовий рівень ізоляції
  • READ_COMMITTED запобігає лише одне, тобто брудне читання
  • REPEATABLE_READ запобігає дві аномалії: брудні читання та неповторювані читання
  • СЕРІАЛІЗАЛЬНІ запобігання всіх трьох аномалій: Брудне зчитування, Не повторюване читання та Фантомне зчитування

Тоді чому б просто не встановити транзакцію СЕРІАЛІЗАЦІЙНО в усі часи? Що ж, відповідь на вищезазначене питання така: СЕРІАЛІЗАЦІЙНА установка робить транзакції дуже повільними , чого ми знову не хочемо.

Насправді витрата часу на транзакцію здійснюється у такій швидкості:

SERIALIZABLE > REPEATABLE_READ > READ_COMMITTED > READ_UNCOMMITTED

Тож налаштування READ_UNCOMMITTED є найшвидшим .


Підсумок

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

Зауважте, що бази даних за замовчуванням мають налаштування REPEATABLE_READ.


1
ОНОВЛЕННЯ або ВИДАЛЕННЯ може відбуватися для повторюваних читання або це лише ОНОВЛЕННЯ?
Діпон Рой

1
ОНОВЛЕННЯ або ВИДАЛЕННЯ обидва можуть відбуватися для повторюваних читання
niket patel

Насправді ми можемо підсумувати, що в середньому випадковий оператор DELETE, виконаний іншою транзакцією в тій самій базі даних, має дуже низьку ймовірність викликати повторне зчитування для поточної транзакції. Але той самий оператор видалення має 100% шанс викликати зчитування Phantom для поточної транзакції. Дивлячись на це так, моє написання трохи неправильне, якщо сприймати це слово за словом. Але ей, я навмисно написав це таким чином, щоб зробити речі більш зрозумілими для читача.
Subhadeep Ray

+1 для простого і зрозумілого пояснення. Однак я думаю, що більшість баз даних (oracle, mysql) мають рівень за замовчуванням за рівнем читання "
Виконано",

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, це означає, що змінити значення рядка, яке B містить, колись B знов прочитає рядок, тож B отримає нове значення, відмінне від першого разу Отримаємо, ми називаємо це неповторюваним, щоб розібратися з проблемою, ми даємо B пам'ятати щось (тому що я не знаю, що ще запам'ятається), коли B почнеться.

Давайте подумаємо над новим рішенням, і ми можемо помітити, що є і нова проблема, тому що ми даємо B пам'ятати щось, тому що б не сталося в A, B не може вплинути, але якщо B хочеться вставити деякі дані в таблицю і B перевірте таблицю, щоб переконатися, що немає запису, але ці дані були вставлені A, тому може виникнути помилка. Ми називаємо це "Фантомним читанням".


0

не повторюване читання - рівень ізоляції, а фантомне зчитування (читання, здійснене за допомогою інших транзакцій) - це поняття (тип зчитування, наприклад, брудне читання чи зчитування знімка). Неповторюваний рівень ізоляції читання дозволяє фантомному читанню, але не брудним читанням чи знімкам знімків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.