Spec-Zone.ru › MySQL 9.2

17.7.2.3 Согласованные чтения без блокировок

Это означает, что InnoDB использует многоверсионность для представления запросу моментального снимка базы данных на определённый момент времени. Запрос видит изменения, внесённые транзакциями, которые были завершены до этого момента, и не видит изменений, внесённых более поздними или незавершенными транзакциями. Исключением из этого правила является то, что запрос видит изменения, внесённые предыдущими операторами в рамках той же транзакции. Это исключение приводит к следующей аномалии: если вы обновляете некоторые строки в таблице, запрос SELECT видит последнюю версию обновлённых строк, но также может видеть более старые версии других строк. Если другие сеансы одновременно обновляют ту же таблицу, аномалия означает, что вы можете увидеть таблицу в состоянии, которое никогда не существовало в базе данных.

Если транзакция находится в режиме REPEATABLE READ (по умолчанию), все согласованные чтения в рамках одной транзакции считывают снимок, созданный первым таким чтением в этой транзакции. Вы можете получить более свежий снимок для своих запросов, завершив текущую транзакцию и после этого выдав новые запросы.

При уровне изоляции READ COMMITTED каждое согласованное чтение в рамках транзакции устанавливает и считывает свой собственный свежий снимок.

Согласованное чтение является режимом по умолчанию, в котором InnoDB обрабатывает операторы SELECT в уровнях изоляции READ COMMITTED и REPEATABLE READ. Согласованное чтение не устанавливает никаких блокировок на таблицах, к которым оно обращается, а поэтому другие сеансы могут свободно изменять эти таблицы одновременно с выполнением согласованного чтения.

Предположим, что вы работаете в режиме изоляции по умолчанию REPEATABLE READ. Когда вы выполняете согласованное чтение (то есть обычный оператор SELECT), InnoDB присваивает вашей транзакции временную метку, согласно которой ваш запрос видит базу данных. Если другая транзакция удаляет строку и завершается после того, как была назначена ваша временная метка, вы не увидите строку как удалённую. Вставки и обновления обрабатываются аналогично.

Примечание

Моментальный снимок состояния базы данных относится к операторам SELECT в рамках транзакции, а не обязательно к другим операторам. Если вы вставляете или изменяете некоторые строки, а затем завершаете эту транзакцию, оператор DELETE или UPDATE, выданный из другой параллельной REPEATABLE READ транзакции, может повлиять на эти только что завершенные строки, даже если сеанс не может их запросить. Если транзакция обновляет или удаляет строки, завершённые другой транзакцией, эти изменения станут видимыми для текущей транзакции. Например, вы можете столкнуться со следующей ситуацией:

SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz';
-- Returns 0: no rows match.
DELETE FROM t1 WHERE c1 = 'xyz';
-- Deletes several rows recently committed by other transaction.

SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc';
-- Returns 0: no rows match.
UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc';
-- Affects 10 rows: another txn just committed 10 rows with 'abc' values.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba';
-- Returns 10: this txn can now see the rows it just updated.

Вы можете продвинуть свою временную метку, завершив свою транзакцию, а затем выполнив ещё один запрос SELECT или START TRANSACTION WITH CONSISTENT SNAPSHOT.

Это называется многоверсионным управлением одновременным доступом.

В следующем примере сеанс А видит строку, вставленную сеансом Б, только когда Б завершает вставку, а А также завершает, так что временная метка проходит за завершение Б.

             Session A              Session B

           SET autocommit=0;      SET autocommit=0;
time
|          SELECT * FROM t;
|          empty set
|                                 INSERT INTO t VALUES (1, 2);
|
v          SELECT * FROM t;
           empty set
                                  COMMIT;

           SELECT * FROM t;
           empty set

           COMMIT;

           SELECT * FROM t;
           ---------------------
           |    1    |    2    |
           ---------------------

Если вы хотите увидеть “самое свежее” состояние базы данных, используйте либо уровень изоляции READ COMMITTED, либо:

SELECT * FROM t FOR SHARE;

При уровне изоляции READ COMMITTED каждое согласованное чтение в рамках транзакции устанавливает и считывает свой собственный свежий снимок. При FOR SHARE происходит блокирующее чтение: сеанс SELECT блокируется до завершения транзакции, содержащей самые свежие строки (см. Раздел 17.7.2.4, «Блокирующие чтения»).

Согласованное чтение не работает с определёнными операторами DDL:

  • Согласованное чтение не работает с операторами DROP TABLE, так как MySQL не может использовать таблицу, которая была удалена, и InnoDB уничтожает таблицу.

  • Согласованное чтение не работает с операциями ALTER TABLE, которые создают временную копию исходной таблицы и удаляют исходную таблицу при создании временной копии. Когда вы повторяете согласованное чтение в рамках транзакции, строки в новой таблице не видны, так как эти строки не существовали в момент, когда был взят снимок транзакции. В этом случае транзакция возвращает ошибку: , “Определение таблицы изменилось, повторите транзакцию”.

Тип чтения изменяется для запросов в предложениях, таких как INSERT INTO ... SELECT, UPDATE ... (SELECT) и CREATE TABLE ... SELECT, которые не задают FOR UPDATE или FOR SHARE:

  • По умолчанию InnoDB использует более жёсткие блокировки для этих операторов, и часть SELECT действует как READ COMMITTED, где каждое согласованное чтение, даже в рамках одной транзакции, устанавливает и считывает свой собственный свежий снимок.

  • Чтобы выполнить чтение без блокировок в таких случаях, установите уровень изоляции транзакции на READ UNCOMMITTED или READ COMMITTED, чтобы избежать установки блокировок на строки, считанные из выбранной таблицы.

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-9.2-en/innodb-consistent-read.html

Spec-Zone.ru

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