一貫性読み取りとは,InnoDB
がマルチバージョンを使用して,ある時点でのデータベースのスナップショットをクエリーに提供することを意味します。クエリーには,その時点よりも前にコミットされたトランザクションによる変更のみが表示され,その時点よりもあとのトランザクションまたはコミットされていないトランザクションによる変更は表示されません。このルールの例外として,同じトランザクション内の以前のステートメントによる変更はクエリーに表示されます。この例外によって,次のような異常が発生します。テーブル内の一部の行を更新すると,更新された行の最新バージョンが选择
,に表示されますがいずれかの行の旧バージョンも表示される可能性があります。その他のセッションで同じテーブルが同時に更新される場合,その異常は,データベースに存在しない状態でテーブルが表示される可能性があることを意味します。
トランザクション分離レベルが可重复读取
(デフォルトのレベル)である場合は,同じトランザクション内のすべての一貫性読み取りで,そのトランザクション内の最初のこのような読み取りで確立されたスナップショットが読み取られます。現在のトランザクションをコミットしたあとに,新しいクエリーを発行すると,クエリーの新しいスナップショットを取得できます。
分離レベルが读过承诺
の場合は,トランザクション内の各一貫性読み取りで,独自の新しいスナップショットが設定され,読み取られます。
一貫性読み取りは,InnoDB
が读过承诺
および可重复读取
分離レベルで选择
ステートメントを処理する際のデフォルトモードです。一貫性読み取りではアクセスされるテーブル上にロックが設定されないため、その他のセッションも、そのテーブル上で一貫性読み取りが実行されるときと同時に、それらのテーブルを自由に変更できます。
デフォルトの可重复读取
分離レベルで実行していると仮定します。一貫性読み取り(つまり,通常の选择
ステートメント)を発行すると,InnoDB
は,クエリーがデータベースを参照するときの基準となるタイムポイントをトランザクションに付与します。タイムポイントが割り当てられたあとに,別のトランザクションが行を削除してコミットした場合は,その行が削除済みとして表示されません。挿入および更新も同様に処理されます。
データベースの状態のスナップショットは,トランザクション内の选择
ステートメントに適用されますが,DMLステートメントには必ずしも適用されるとは限りません。一部の行を挿入または変更してから,そのトランザクションをコミットする場合は,そのセッションでクエリーが実行される可能性がない場合でも,別の並列実行可重复读取
トランザクションから発行された删除
または更新
ステートメントによって,コミットされたばかりの行が影響を受ける可能性があります。トランザクションによって別のトランザクションでコミットされた行が更新または削除されると、これらの変更を現在のトランザクションに表示できるようになります。たとえば、次のような状況が発生する可能性があります。
SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz';——返回0:没有匹配的行。DELETE FROM t1 WHERE c1 = 'xyz';删除最近由其他事务提交的行。SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc';——返回0:没有匹配的行。UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc';——影响10行:另一个txn刚刚提交了10行“abc”值。SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba';——返回10:这个txn现在可以看到它刚刚更新的行。
トランザクションをコミットしてから,別の选择
または使用一致性快照启动事务
を実行すると,タイムポイントを進めることができます。
これは,マルチバージョン並列処理制御と呼ばれます。
次の例では,セッションBが挿入をコミットし,セッション一も同様にコミットした場合にのみ,Bによって挿入された行が一に表示されます。これにより,タイムポイントがBのコミットよりも先に進みます。
会话A会话B SET autocommit=0;设置自动提交= 0;时间| SELECT * FROM t;| set | INSERT INTO t VALUES (1, 2);| v SELECT * FROM t;空集提交;SELECT * FROM t;空集提交;SELECT * FROM t;--------------------- | 1 | 2 | --------------------- 1行组
データベースの「最新」状態を確認する場合は,读过承诺
分離レベルとロック読み取りのいずれかを使用します。
SELECT * FROM t LOCK IN共享模式;
分離レベルが读过承诺
の場合は,トランザクション内の各一貫性読み取りで,独自の新しいスナップショットが設定され,読み取られます。锁定共享模式
の場合は,代わりにロック読み取りが発生します。选择
は,最新の行を含むトランザクションが終了するまでブロックされます(セクション14.2.5”ロック読み取り(选择…更新および选择……锁定共享模式)"を参照)。
特定のDDLステートメントでは,一貫性読み取りが機能しません。
删除表
ではMySQLが削除されたテーブルを使用できず,そのテーブルはInnoDB
によって破棄されるため,一貫性読み取りが機能しません。ALTER TABLE
では,そのステートメントで元のテーブルの一時コピーが作成され,元のテーブルは一時コピーが構築されるときに削除されるため,一貫性読み取りが機能しません。トランザクション内で一貫性読み取りを再発行しても、新しいテーブル内の行はトランザクションのスナップショット取得されたときには存在していなかったため、表示できません。MySQL 5.6.6 の時点では、この場合に、トランザクションから「表定义已更改,请重试事务」というER_TABLE_DEF_CHANGED
エラーが返されます。
更新
または锁定共享模式
を指定しない插入……选择
、更新……(选择)
、创建表……选择
などの句での選択では,読み取りのタイプが異なります。
デフォルトでは,
InnoDB
はより強固なロックを使用し,选择
部分は读过承诺
と同様に機能します。この場合,同じトランザクション内でも,各一貫性読み取りで独自の新しいスナップショットが設定され,読み取られます。このような場合に一貫性読み取りを使用するには,
innodb_locks_unsafe_for_binlog
オプションを有効にし,トランザクションの分離レベルを读未提交
、读过承诺
,または可重复读取
(つまり,可序列化的
以外のすべて)に設定します。この場合,選択したテーブルから読み取られた行には,ロックが設定されません。