一貫性読み取りとは、InnoDB
がそのマルチバージョニング機能を使用して、ある時点でのデータベースのスナップショットをクエリーに提示することを意味します。クエリーには、その時点より前にコミットされたトランザクションによる変更のみが示され、その時点より後のトランザクションまたはコミットされていないトランザクションによる変更は示されません。例外として、クエリーを発行したトランザクション自体による変更はクエリーに示されます。この例外によって次のような異常な状況が生まれます。ユーザーがテーブル内の何行かを更新してから
SELECT
を実行すると、それらの更新された行については最新版が表示されますが、同時に任意の行の古いバージョンも表示される可能性あります。もし別のセッションが同時に同じテーブルを更新すると、今までとは違う状態のテーブルをデータベース内で確認するかもしれなという例外があるかもしれません。
トランザクション遮断レベルが
REPEATABLE
READ
(デフォルトのレベル)
の場合、同じトランザクション内のすべての一貫性読み取りでは、そのトランザクション内のそのような読み取りの最初のものによって確立されたスナップショットが読み取られます。現在のトランザクションをコミットしその後新しいクエリーを発行することで、クエリーにより新鮮なスナップショットを得ることができます。
遮断レベルが READ
COMMITTED
の場合、あるトランザクション内の各一貫性読み取りでは、それぞれ独自の新しいスナップショットの設定と読み取りが行われます。
InnoDB
が
READ COMMITTED
と REPEATABLE
READ
遮断レベル内で
SELECT
ステートメントを処理する中で、一貫性読み取りはデフォルトのモードです。一貫性読み取りはそれがアクセスするテーブル上に一切ロックを設定しないので、別のセッションは、そのテーブル上で一貫性読み取りが行われているのと同時にそれらのテーブルを自由に変更することができます。
デフォルトの
REPEATABLE
READ
遮断レベルで起動していると仮定してください。一貫性読み取り
(通常の SELECT
ステートメント)
では、InnoDB
は、クエリーがデータベースを参照するときの基準となるタイムポイントをトランザクションに与えます。こうして、タイムポイントが割り当てられたあとに、ほかのトランザクションが行を削除してコミットしたとしても、一度読み取った内容は変わりません。挿入と更新も同じように扱われます。
割り当てられたタイムポイントを先に進めるには、トランザクションをコミットし、新たな
SELECT
を実行します。
これは、マルチバージョン並行処理制御 と呼ばれています。
次の例では、セッション A は、セッション A と B の両方が挿入をコミットしたときだけ、B によって挿入された行を確認することができ、それによってタイムポイントは B のコミットよりも先に進みます。
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 | --------------------- 1 row in set
データベースの 「最新の」
状態を確認したければ、READ
COMMITTED
遮断レベルかロック読み取りのどちらかを利用しなければいけません:
SELECT * FROM t LOCK IN SHARE MODE;
遮断レベルが READ
COMMITTED
の場合、あるトランザクション内の各一貫性読み取りでは、それぞれ独自の新しいスナップショットの設定と読み取りが行われます。LOCK
IN SHARE MODE
の場合は代わりにロック読み取りが発生します。SELECT
は、最新の行を含むトランザクションが終了するまでブロックします
(項9.8.3. 「SELECT ... FOR
UPDATE
と
SELECT
... LOCK IN SHARE MODE
ロック読み取り」を参照)。
一貫性読み取りは
DROP TABLE
や
ALTER TABLE
全体には機能しません。
MySQL
が削除されたテーブルを利用することができず、InnoDB
がそのテーブルを破壊するため、一貫性読み取りは
DROP TABLE
全体には機能しません。
ALTER TABLE
は元テーブルの一時コピーを作成し、それができたときに元テーブルを破壊することで機能するため、一貫性読み取りは
ALTER TABLE
全体には機能しません。トランザクション内で一貫性読み取りを再発行するとき、新しいテーブル内の行はトランザクションのスナップショットが撮られたときに存在していなかったために見ることができません。
innodb_locks_unsafe_for_binlog
オプションが設定されていて、かつトランザクションの遮断レベルが
SERIALIZABLE
に設定されていない場合、InnoDB
は、FOR UPDATE
や
LOCK IN SHARE MODE
が指定されていない
INSERT
INTO ...
SELECT
、UPDATE
...
(SELECT)
、CREATE
TABLE ... SELECT
などの節に含まれる選択に対し、一貫性読み取りを使用します。したがって、選択されたテーブルから読み取られた行にはロックは設定されていません。それ以外の場合、InnoDB
はより強いロックを使用し、SELECT
部分は READ
COMMITTED
のような役割を果たし、各一貫性読み取りでは同じトランザクション内であっても、独自の新しいスナップショットの設定と読み取りが行われます。