Де InnoDB зберігає дані транзакцій, перш ніж зробити їх?


12

Я зробив кілька тестів, використовуючи READ_COMMITTEDі READ_UNCOMMITTEDвдома, використовуючи технологію JDBC.

Я бачу, що READ_UNCOMMITTEDнасправді можна прочитати невідомі дані, наприклад, дані про якусь транзакцію ще не здійснено (може виконати UPDATE-запит).

Запитання

  • Де зберігаються неподані дані, щоб READ_UNCOMMITTEDтранзакція могла прочитати невідомі дані з іншої транзакції?
  • Чому READ_COMMITTEDтранзакція не може зчитувати неподані дані, тобто виконувати "брудне читання"? Який механізм застосовує це обмеження?

Відповіді:


11

" Де зберігаються непослані дані, таким чином, що транзакція READ_UNCOMMITTED може читати невідомі дані з іншої транзакції? "

Нові незапущені записи (кластеризовані ПК) розглядаються як "поточна" версія запису на сторінці. Таким чином, вони можуть зберігатися в буферному пулі та / або в просторі таблиць (наприклад, tablename.ibd). Операції, для яких потім потрібно створити знімок / перегляд у будь-якому, крім READ-UNCOMMITTED, потрібно побудувати попередню версію рядка (за списком історії), використовуючи записи UNDO (зберігаються в системному просторі таблиць ). Під час читання невідправленого запису InnoDB також може знадобитися прочитати деякі незапущені записи вторинного індексу з буфера зміни та застосувати їх перед тим, як подати запис назад користувачеві.

Саме така поведінка може зробити відкати в InnoDB порівняно дорогими. Це великий фактор, який також може призвести до потенційних проблем з ефективністю тривалих запущених транзакцій, що містять оновлені записи, оскільки ці транзакції блокують операції очищення, а список історії старих версій записів зростає, а записи UNDO, необхідні для відновлення цих старих версій на вимогу, буде продовжувати зростати. Це уповільнює нові транзакції, для яких потрібно прочитати старішу / скоєну версію запису, оскільки їм необхідно пройти більш довгий і довший список історії - який є окремо пов'язаним списком записів UNDO - і зробити більше роботи для відновлення стара версія запису. Отже, ви використовуєте багато циклів процесора (не кажучи вже про внутрішні примітивні блокування: mutexe, rw_locks, semaphores тощо).

Сподіваємось, це має сенс? :)

Як FYI, в MySQL 5.7 ви можете перемістити табличний простір UNDO та журнали з системного простору таблиць і автоматично їх обрізати. Вони можуть зрости досить великими, якщо у вас є тривала транзакція, яка перешкоджає очищенню операцій, що призводить до дуже тривалої та постійно зростаючої довжини списку історії. Зберігання їх у системному просторі таблиць було найпоширенішою причиною величезного / зростаючого файлу ibdata1, який, у свою чергу, не може бути усічений / зменшений / вакуумований, щоб згодом повернути цей простір.


4

Ти запитав

де зберігаються непослані дані, таким чином, що транзакція READ_UNCOMMITTED може читати невідомі дані з іншої транзакції?

Щоб відповісти на ваше запитання, вам потрібно знати, як виглядає архітектура InnoDB.

Наведена нижче картина була створена роками тому КТО Percona Вадимом Ткаченком

Архітектура InnoDB

Відповідно до Документації MySQL про модель транзакцій та блокування InnoDB

COMMIT означає, що зміни, внесені в поточній транзакції, стають постійними та стають видимими для інших сесій. З іншого боку, оператор ROLLBACK скасовує всі зміни, внесені поточною транзакцією. І COMMIT, і ROLLBACK випускають усі блоки InnoDB, які були встановлені під час поточної транзакції.

Оскільки COMMIT і ROLLBACK регулюють видимість даних, ЧИТАТИ ЗВ'ЯЗАНО та ПРОЧИТАТИ НЕЗАКОМНОГО доведеться покладатися на структури та механізми, що фіксують зміни

  1. Відхилення сегментів / Скасування місця
  2. Повторити журнали
  3. Пропуски блокуються щодо залучених таблиць

Відчетні сегменти та скасувати пробіл знають, як виглядали змінилися дані до застосування змін. Redo Logs знає, які зміни потрібно просунути вперед, щоб дані з’явились.

Ви також запитували

чому не можливо для транзакції READ_COMMITTED зчитувати непідписані дані, тобто виконувати "брудне читання"? Який механізм застосовує це обмеження?

Повторюються журнали, скасувати пробіл та заблоковані рядки. Ви також повинні врахувати, що він InnoDB Buffer Pool (де ви можете вимірювати брудні сторінки за допомогою innodb_max_dirty_pages_pct , innodb_buffer_pool_pages_dirty та innodb_buffer_pool_bytes_dirty ).

Зважаючи на це, ЧИТАЙТЕ ЗНАЧЕНО, що дані з'являться назавжди. Тому не потрібно шукати брудні сторінки, які не були вчинені. ЧИТАЙТЕ ЗАПОВІДНО, це буде не що інше, як забруднене читання. ЧИТАЙТЕ НЕЗАКОМНО, і надалі знатимуть, які рядки мають бути заблоковані та які повторні журнали були прочитані чи проігноровані, щоб зробити дані видимими.

Щоб повністю зрозуміти блокування рядків для управління ізоляцією, будь ласка, прочитайте модель транзакцій InnoDB та блокування


1
По-перше, дякую за вашу відповідь та модифікацію моєї публікації ... Отже, перед COMMIT, зміни не помітні для інших користувачів системи? Тут користувач буквально означає транзакцію, правда? Оскільки READ UNCOMMITTED може читати невідомі дані, звідки цей рівень ізоляції читає ці дані? Чи може бути декілька джерел непосланих даних для певного елемента даних у базі даних? Якщо так, то який невідомий фрагмент даних буде потім прочитаний?
Шучжен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.