Где InnoDB хранит данные транзакции до ее совершения?

12

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

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

Вопросы

  • Где хранятся незафиксированные данные, чтобы READ_UNCOMMITTEDтранзакция могла считывать незафиксированные данные из другой транзакции?
  • Почему READ_COMMITTEDтранзакция не может прочитать незафиксированные данные, то есть выполнить «грязное чтение»? Какой механизм обеспечивает это ограничение?
Shuzheng
источник

Ответы:

11

« Где хранятся незафиксированные данные, чтобы транзакция READ_UNCOMMITTED могла считывать незафиксированные данные из другой транзакции? »

Версии новой незафиксированной записи (кластеризованного PK) рассматриваются как «текущая» версия записи на странице. Таким образом, они могут храниться в пуле буферов и / или в табличном пространстве (например, tablename.ibd). Транзакции, которые затем должны создавать снимок / представление в любом другом месте, кроме READ-UNCOMMITTED, должны создавать предыдущую версию строки (следуя списку истории) с использованием записей UNDO (хранящихся в системном табличном пространстве ). При чтении незафиксированной записи InnoDB также может потребоваться прочитать некоторые незафиксированные записи вторичного индекса из буфера изменений и применить их, прежде чем представить запись обратно пользователю.

Именно такое поведение может сделать откат в InnoDB относительно дорогим. Это важный фактор, который также может привести к потенциальным проблемам с производительностью из-за длительных бездействующих транзакций, которые содержат обновленные записи, так как эти транзакции будут блокировать операции очистки, а список хронологии старых версий записей будет расти, а записи UNDO, необходимые для восстановления этих старых версий по запросу, будет продолжать расти. Это замедляет новые транзакции, которые должны прочитать более старую / подтвержденную версию записи, поскольку им необходимо пройти по более длинному и длинному списку истории - который является однозначно связанным списком записей UNDO - и выполнять больше работы для восстановления старая версия записи. Таким образом, вы в конечном итоге используете много циклов ЦП (не говоря уже о внутренних блокирующих примитивах: мьютексах, rw_locks, семафорах и т. Д.).

Надеюсь, это имеет смысл? :)

Как FYI, в MySQL 5.7 вы можете перемещать табличное пространство UNDO и выходить из системного табличного пространства и автоматически их усекать. Они могут стать довольно большими, если у вас есть длительная транзакция, которая предотвращает операции очистки, что приводит к очень длинной и постоянно растущей длине списка истории. Хранение их в системном табличном пространстве было единственной наиболее распространенной причиной огромного / растущего файла ibdata1, который, в свою очередь, не может быть усечен / уменьшен / очищен для последующего освобождения этого пространства.

Мэтт Лорд
источник
4

Ты спрашивал

где хранятся незафиксированные данные, чтобы транзакция READ_UNCOMMITTED могла считывать незафиксированные данные из другой транзакции?

Чтобы ответить на ваш вопрос, вам нужно знать, как выглядит архитектура InnoDB.

Следующая картина была создана лет назад техническим директором Percona Вадимом Ткаченко

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

Согласно документации MySQL о модели транзакций InnoDB и блокировке

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

Поскольку COMMIT и ROLLBACK управляют видимостью данных, READ COMMITTED и READ UNCOMMITTED должны полагаться на структуры и механизмы, которые регистрируют изменения

  1. Откат сегментов / Отменить пробел
  2. Redo Logs
  3. Пробелы в замках против задействованных таблиц

Сегменты отката и Undo Space будут знать, на что были похожи измененные данные, прежде чем изменения будут применены. Журналы повторов будут знать, какие изменения необходимо перенести, чтобы данные обновлялись.

Вы также спросили

почему транзакция READ_COMMITTED не может прочитать незафиксированные данные, то есть выполнить «грязное чтение»? Какой механизм применяет это ограничение?

В игру вступают Redo Logs, Undo Space и Locked. Вы также должны рассмотреть пул буферов InnoDB (где вы можете измерить грязные страницы с помощью innodb_max_dirty_pages_pct , innodb_buffer_pool_pages_dirty и innodb_buffer_pool_bytes_dirty ).

В свете этого, READ COMMITTED будет знать, какие данные появляются навсегда. Поэтому нет необходимости искать грязные страницы, которые не были зафиксированы. READ COMMITED - это не более чем грязное чтение, которое было зафиксировано. READ UNCOMMITTED продолжал бы знать, какие строки должны быть заблокированы, а какие журналы повторов прочитаны или проигнорированы, чтобы сделать данные видимыми.

Чтобы полностью понять блокировку строк для управления изоляцией, прочитайте Модель транзакций InnoDB и Блокировка

RolandoMySQLDBA
источник
1
Во-первых, спасибо за ваш ответ и модификацию моего поста ... Значит, до коммита изменения не видны другим пользователям системы? Здесь пользователь буквально означает транзакцию, верно? Так как READ UNCOMMITTED может читать незафиксированные данные, где этот уровень изоляции читает эти данные? Может ли быть несколько источников незафиксированных данных для определенного элемента данных в базе данных? Если да, то какой незафиксированный фрагмент данных будет прочитан?
Shuzheng