предисловие
В прошлой статье упоминалось, что уровень изоляции RR MySQL решает проблему фантомного чтения через MVCC+Next-key Locks, сейчас я расскажу вам, что это за два механизма.
MVCC (управление параллелизмом нескольких версий)
Multi-Version Concurrency Control (MVCC) — это особый способ для механизма хранения MySQL InnoDB реализовать уровни изоляции, которые используются для реализации двух уровней изоляции фиксированного чтения и повторяемого чтения. Уровень изоляции незафиксированного чтения всегда считывает последнюю строку данных без использования MVCC. Сериализуемый уровень изоляции требует, чтобы все прочитанные строки были заблокированы, чего нельзя добиться с помощью одного лишь MVCC.
Большинство реализаций транзакционного механизма хранения MySQL не являются простыми блокировками на уровне строк. Основываясь на соображении улучшения параллелизма, управление параллелизмом нескольких версий (MVCC) обычно реализуется одновременно, включая Oracle и PostgreSQL. Однако реализации различаются.
Реализация MVCC достигается за счет сохранения моментальных снимков данных в определенный момент времени. Другими словами, независимо от того, как долго длится время реализации, данные, видимые каждой вещью, непротиворечивы.
Делятся на оптимистичный (оптимистичный) контроль параллелизма и пессимистический (прессимистический) контроль параллелизма.
Как работает MVCC:
MVCC InnoDB достигается за счет сохранения двух скрытых столбцов за каждой строкой записей. Один из этих двух столбцов содержит время создания строки, а другой — время истечения срока действия (время удаления) строки. Конечно, хранится не реальное время, а номер версии системы. Каждый раз, когда запускается новая транзакция, номер версии системы будет добавляться автоматически. Номер версии системы в начале транзакции будет использоваться в качестве номера версии транзакции для запроса номера версии каждой строки записей для сравнения.
номер версии
Номер версии системы:Это возрастающее число.Каждый раз, когда запускается новая транзакция, номер версии системы будет автоматически увеличиваться.
Номер версии транзакции:Номер версии системы на момент запуска транзакции.
скрытый столбец
MVCC хранит два скрытых столбца за каждой строкой записей, используемых для хранения двух номеров версий:
- Номер версии создания: при создании строки данных назначьте текущий номер версии системы в качестве номера версии создания.
- Удалить номер версии: при удалении строки данных назначьте текущий номер версии системы в качестве номера версии для удаления. Если номер удаленной версии моментального снимка больше, чем номер версии текущей транзакции, снимок является действительным, в противном случае снимок был удален.
Как MVCC работает на уровне изоляции REPEATABLE READ:
Важно понимать, что при запуске новой транзакции номер версии транзакции должен быть больше, чем номер версии текущего моментального снимка всех строк данных.
1. SELECT
InnoDB проверяет каждую строку на соответствие следующим условиям:
1. InnoDB находит только те строки данных, версия которых предшествует текущей версии транзакции, что можетУбедитесь, что строки, прочитанные транзакцией, либо уже существовали до ее запуска, либо были вставлены или изменены самой транзакцией., транзакция не увидит строки, вставленные после запуска транзакции.
2. Номер версии удаления строки либо не определен, либо больше номера версии текущей транзакции, что можетУбедитесь, что строки, прочитанные транзакцией, не удаляются до начала транзакции., транзакция не увидит строки данных, срок действия которых истек до начала транзакции.
Будут опрошены только те, которые соответствуют двум вышеуказанным условиям.
2. INSERT
Используйте текущий номер версии системы в качестве номера версии создания моментального снимка строки данных.
3. DELETE
Используйте номер текущей версии системы в качестве номера версии для удаления моментального снимка строки данных.
4. UPDATE
Текущий номер версии системы используется в качестве номера версии удаления моментального снимка строки данных перед обновлением, а номер текущей версии системы используется в качестве номера версии создания моментального снимка строки данных после обновления.Это можно понимать как выполнение сначала DELETE, а затем выполнение INSERT..
Сохраните эти два номера версии, чтобы не было необходимости блокировать большинство операций. Упрощает манипулирование данными, обеспечивает высокую производительность и гарантирует, что будут прочитаны только те строки, которые необходимы для соединения. Недостатком является то, что для каждой строки записей требуется дополнительное место для хранения, больше работы по проверке строк и некоторые дополнительные работы по обслуживанию.
MVCC работает только при двух уровнях изоляции: COMMITTED READ (фиксация чтения) и REPEATABLE READ (повторяемое чтение).
Можно считать, что MVCC — это вариант блокировок на уровне строк, но во многих случаях он позволяет избежать операций блокировки и имеет меньшие накладные расходы. Хотя механизмы реализации разных баз данных различаются, в большинстве из них реализованы неблокирующие операции чтения (чтение без блокировки, и можно избежать неповторяющихся чтений и фантомных чтений), а операции записи блокируют только необходимые строки (записи должны быть заблокированы, иначе одновременная запись разными транзакциями приведет к несогласованности данных).
Чтение моментального снимка и текущее чтение
На уровне RR с помощью механизма MVCC, хотя данные могут считываться повторно, данные, которые мы читаем, могут быть историческими данными, а не последними данными в базе данных. Такой способ чтения исторических данных мы называемснимок прочитан, а способ чтения последней версии данных базы данных называетсятекущее чтение.
1. Чтение снимка
При выполнении операции выбора innodb по умолчанию выполнит чтение снимка и запишет результаты после выбора.После этого данные этого снимка будут возвращены при выборе, даже если будут отправлены другие транзакции, это не повлияет на данные текущего выбора Достигается повторяющееся чтение. Моментальный снимок создается, когда выбор выполняется в первый раз, то есть, если A запускает транзакцию, а затем не выполняет никакой операции, в это время B вставляет часть данных, а затем фиксирует ее. , когда A выполнит выбор, возвращаемые данные будут: Будет часть данных, добавленная B. После этого не имеет значения, есть ли другие фиксации транзакций, потому что снимок был сгенерирован, и последующие выборки основаны на снимке.
Данные в моментальном снимке считываются с помощью MVCC, что может уменьшить накладные расходы, вызванные блокировкой.
select * from table ...;
2. Текущее чтение
Для операций, изменяющих данные (обновление, вставка, удаление), используется текущий режим чтения. При выполнении этих операций считываются последние записи, и даже могут быть запрошены данные, представленные другими транзакциями. Предположим, вы хотите обновить запись, но данные были удалены и зафиксированы в другой транзакции, если обновление будет конфликтовать, поэтому вам нужно знать последние данные при обновлении.
Последние данные считываются и должны быть заблокированы. Первый оператор ниже должен добавить блокировку S, а остальные должны добавить блокировку X.
select * from table where ? lock in share mode;
select * from table where ? for update;
insert;
update;
delete;
Как исправить галлюцинации
Очевидно, что уровень изоляции повторяющегося чтения не может полностью решить проблему фантомного чтения, если вам нужно решить фантомное чтение, есть два пути:
- Уровень изоляции с использованием сериализованного чтения
- MVCC+блокировки следующего ключа: блокировки следующего ключа состоят из блокировок записи (индексных блокировок) и гэп-блокировок (гэп-блокировок, каждый раз блокирует не только данные, которые нужно использовать, но и блокирует данные рядом с этими данными)
InnoDB имеет три алгоритма блокировки строк:
1, блокировка записи: блокировка записи одной строки.
2, Gap Lock: Gap Lock, блокирует диапазон, но не включает саму запись. Блокировка GAP предназначена для предотвращения фантомного чтения двух текущих операций чтения одной и той же транзакции.
3, блокировка следующей клавиши: 1+2, блокировка диапазона и блокировка самой записи. Для запроса строки используется этот метод, основная цель которого — решить проблему фантомного чтения.
Record Locks
Блокирует индекс записи, а не саму запись.
Если таблица не проиндексирована, InnoDB автоматически создаст скрытый кластеризованный индекс по первичному ключу, поэтому можно будет использовать блокировку записей.
Gap Locks
Блокирует промежутки между индексами, но не сами индексы. Например, когда одна транзакция выполняет следующий оператор, другие транзакции не могут вставить 15 в t.c.
SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
Next-Key Locks
Next-Key Locks — это реализация блокировки механизма хранения MySQL InnoDB.
MVCC не может решить проблему фантомного чтения, и для решения этой проблемы существуют блокировки Next-Key. На уровне изоляции REPEATABLE READ использование MVCC + Next-Key Locks может решить проблему фантомного чтения.
Когда индекс запроса содержит уникальный атрибут, блокировка следующего ключа будет оптимизирована и понижена до блокировки записи, то есть будет заблокирован только сам индекс, а не диапазон.
Это комбинация блокировок записей и блокировок промежутков, которая не только блокирует индекс записи, но также блокирует разрыв между индексами.
Создайте новую таблицу:
CREATE TABLE `test` (
`id` int(11) primary key auto_increment,
`xid` int, KEY `xid` (`xid`) )
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into test(xid) values (1), (3), (5), (8), (11);
Обратите внимание, что для xid есть индекс, потому что алгоритм всегда будет блокировать запись индекса.
Теперь диапазон, в котором этот индекс может быть заблокирован, выглядит следующим образом:
(-∞, 1], (1, 3], (3, 5], (5, 8], (8, 11], (11, +∞)
Откройте транзакцию для выполнения SQL одним из следующих способов:
Диапазон, который будет заблокирован после выполнения сеанса A:
(5, 8], (8, 11]
Помимо блокировки диапазона, где находится 8, он также блокирует следующий диапазон, так называемый Next-Key.
Таким образом, Session B заблокируется, когда достигнет шестого шага, пропустит шестой шаг и не выполнится, а седьмой шаг также заблокируется, но не заблокирует восьмой шаг, а девятый шаг не заблокируется.
Приведенный выше результат выглядит не так, как ожидалось, потому что значение 11 находится в интервале (8, 11), а значение 5 не находится в интервале (5, 8).
Посмотрите на картинку ниже, чтобы понять:
Заблокированный диапазон оператора SQL — (5,8), а следующий диапазон значений ключа — (8,11], поэтому при вставке значений между 5 и 11 он будет заблокирован и потребует ожидания. То есть: вставка 5, 6, 7, 8, 9, 10 будет заблокирована.Вставка значений вне этого диапазона является нормальным явлением.
резюме
В этой статье обобщаются три алгоритма блокировки строк в MVCC и InnoDB. Эти знания относятся к базовому уровню MySQL. При таком понимании использование MySQL может быть более удобным в будущем. Последний вопрос выше: почему он не будет заблокирован когда xid равен 11. Все еще есть немного непонимания.Объяснение, данное другими блоггерами, заключается в том, что идентификатор является самовозрастающим, а дерево B + innodb упорядочено, поэтому оно не будет блокировать последующие вставки. Это объяснение все еще требует, чтобы я вернулся и посмотрел на подробное описание реализации блокировок следующего ключа в «mysq technology Insider», прежде чем дать более разумное объяснение.
Ссылка из