Documentation Home
MySQL 8.0 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 36.1Mb
PDF (A4) - 36.2Mb


このページは機械翻訳したものです。

15.7.2.3 一貫性非ロック読み取り

一貫性読み取りとは、InnoDB がマルチバージョンを使用して、ある時点でのデータベースのスナップショットをクエリーに提供することを意味します。 クエリーには、その時点よりも前にコミットされたトランザクションによる変更のみが表示され、その時点よりもあとのトランザクションまたはコミットされていないトランザクションによる変更は表示されません。 このルールの例外として、同じトランザクション内の以前のステートメントによる変更はクエリーに表示されます。 この例外によって、次のような異常が発生します。テーブル内の一部の行を更新すると、更新された行の最新バージョンが SELECT に表示されますが、いずれかの行の旧バージョンも表示される可能性があります。 その他のセッションで同じテーブルが同時に更新される場合、その異常は、データベースに存在しない状態でテーブルが表示される可能性があることを意味します。

トランザクション分離レベルREPEATABLE READ (デフォルトのレベル) である場合は、同じトランザクション内のすべての一貫性読み取りで、そのトランザクション内の最初のこのような読み取りで確立されたスナップショットが読み取られます。 現在のトランザクションをコミットしたあとに、新しいクエリーを発行すると、クエリーの新しいスナップショットを取得できます。

分離レベルが READ COMMITTED の場合は、トランザクション内の各一貫性読み取りで、独自の新しいスナップショットが設定され、読み取られます。

一貫性読み取りは、InnoDBREAD COMMITTED および REPEATABLE READ 分離レベルで SELECT ステートメントを処理する際のデフォルトモードです。 一貫性読み取りではアクセスされるテーブル上にロックが設定されないため、その他のセッションも、そのテーブル上で一貫性読み取りが実行されるときと同時に、それらのテーブルを自由に変更できます。

デフォルトの REPEATABLE READ 分離レベルで実行していると仮定します。 一貫性読み取り (つまり、通常の SELECT ステートメント) を発行すると、InnoDB は、クエリーがデータベースを参照するときの基準となるタイムポイントをトランザクションに付与します。 タイムポイントが割り当てられたあとに、別のトランザクションが行を削除してコミットした場合は、その行が削除済みとして表示されません。 挿入および更新も同様に処理されます。

注記

データベースの状態のスナップショットは、トランザクション内の SELECT ステートメントに適用されますが、DML ステートメントには必ずしも適用されるとは限りません。 一部の行を挿入または変更してから、そのトランザクションをコミットする場合は、そのセッションでクエリーが実行される可能性がない場合でも、別の並列実行 REPEATABLE READ トランザクションから発行された DELETE または UPDATE ステートメントによって、コミットされたばかりの行が影響を受ける可能性があります。 トランザクションによって別のトランザクションでコミットされた行が更新または削除されると、これらの変更を現在のトランザクションに表示できるようになります。 たとえば、次のような状況が発生する可能性があります。

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 を実行すると、タイムポイントを進めることができます。

これは、マルチバージョン並列処理制御と呼ばれます。

次の例では、セッション B が挿入をコミットし、セッション A も同様にコミットした場合にのみ、B によって挿入された行が A に表示されます。これにより、タイムポイントが 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    |
           ---------------------

データベースの最新状態を確認する場合は、READ COMMITTED 分離レベルとロック読み取りのいずれかを使用します。

SELECT * FROM t FOR SHARE;

分離レベルが READ COMMITTED の場合は、トランザクション内の各一貫性読み取りで、独自の新しいスナップショットが設定され、読み取られます。 FOR SHARE では、かわりにロック読取りが発生: SELECT は、最新の行を含むトランザクションが終了するまでブロックされます (セクション15.7.2.4「読取りのロック」 を参照)。

特定の DDL ステートメントでは、一貫性読み取りが機能しません。

  • DROP TABLE では、MySQL が削除されたテーブルを使用できず、そのテーブルは InnoDB によって破棄されるため、一貫性読み取りが機能しません。

  • 読取り一貫性は、元のテーブルの一時コピーを作成し、一時コピーの作成時に元のテーブルを削除する ALTER TABLE 操作では機能しません。 トランザクション内で一貫性読み取りを再発行しても、新しいテーブル内の行はトランザクションのスナップショット取得されたときには存在していなかったため、表示できません。 この場合、トランザクションはエラーを返します: ER_TABLE_DEF_CHANGEDテーブル定義が変更されました。トランザクションを再試行してください

読取りのタイプは、FOR UPDATE または FOR SHARE を指定しない INSERT INTO ... SELECTUPDATE ... (SELECT) および CREATE TABLE ... SELECT などの句での選択によって異なります:

  • デフォルトでは、InnoDB はこれらのステートメントに対してより強力なロックを使用し、SELECT 部分は READ COMMITTED のように動作します。この場合、各読取り一貫性は、同じトランザクション内であっても、独自の新しいスナップショットを設定および読み取ります。

  • このような場合に非ロック読取りを実行するには、トランザクションの分離レベルを READ UNCOMMITTED または READ COMMITTED に設定して、選択したテーブルから読み取られた行にロックを設定しないようにします。