Spec-Zone.ru › MySQL 8.4

17.7.4 Призрачные строки

Так называемая проблема призрачных строк возникает в рамках транзакции, когда один и тот же запрос возвращает разные наборы строк в разное время. Например, если оператор SELECT выполняется дважды, но во второй раз возвращает строку, которая не была возвращена в первый раз, эта строка является “призрачной” строкой.

Предположим, что в таблице child есть индекс по столбцу id, и вы хотите прочитать и заблокировать все строки из таблицы, имеющие идентификатор, больший 100, с намерением позже обновить некоторые столбцы в выбранных строках:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

Запрос сканирует индекс, начиная с первой записи, где значение id больше 100. Предположим, что таблица содержит строки со значениями id 90 и 102. Если блокировки, установленные на записи индекса в сканируемом диапазоне, не блокируют вставки, сделанные в промежутках (в данном случае, промежуток между 90 и 102), другая сессия может вставить новую строку в таблицу с значением id 101. Если выполнить тот же оператор SELECT в рамках той же транзакции, вы увидите новую строку со значением id 101 (призрачную строку) в наборе результатов, возвращённом запросом. Если считать набор строк за единицу данных, новая призрачная строка нарушает принцип изоляции транзакций, согласно которому транзакция должна выполняться так, чтобы данные, которые она читает, не изменялись во время транзакции.

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

Когда InnoDB сканирует индекс, она также может заблокировать промежуток после последней записи в индексе. Именно это происходит в предыдущем примере: Чтобы предотвратить любые вставки в таблицу, где значение id было бы больше 100, блокировки, установленные InnoDB, включают блокировку промежутка, следующего за значением id 102.

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

Блокировка промежутков может быть отключена, как обсуждалось в разделе 17.7.1 «Блокировка InnoDB». Это может привести к проблемам с призрачными строками, потому что другие сессии могут вставлять новые строки в промежутки при отключённой блокировке промежутков.

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-8.4-en/innodb-next-key-locking.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API