重要
このページは英語版のページを機械翻訳しています。原文はこちらからご覧ください。

TiDBトランザクション分離レベル

トランザクション分離は、データベーストランザクション処理の基盤の1つです。分離は、トランザクションの4つの主要なプロパティの1つです(一般にと呼ばれます)。

SQL-92標準では、トランザクション分離の4つのレベルが定義されています。コミットされていない読み取り、コミットされた読み取り、繰り返し可能な読み取り、およびシリアル化可能です。詳細については、次の表を参照してください。

分離レベルダーティライトダーティリードファジーリードファントム
コミットされていない読み取りありえない可能可能可能
コミット済みを読むありえないありえない可能可能
繰り返し読むありえないありえないありえない可能
シリアル化可能ありえないありえないありえないありえない

TiDBは、MySQLとの互換性のためにREPEATABLE-READとしてアドバタイズするスナップショットアイソレーション(SI)整合性を実装します。これは、 ANSI反復可能読み取り分離レベルおよびMySQLの繰り返し可能な読み取りレベルとは異なります。

ノート:

TiDB v3.0では、トランザクションの自動再試行はデフォルトで無効になっています。自動再試行を有効にすると、トランザクション分離レベルが損なわれる可能性があるため、お勧めしません。詳細はトランザクションの再試行を参照してください。

TiDB v3.0.8から、新しく作成されたTiDBクラスターはデフォルトで悲観的なトランザクションモードを使用します。現在の読み取り( for update読み取り)は繰り返し不可の読み取りです。詳細は悲観的なトランザクションモードを参照してください。

繰り返し可能な読み取り分離レベル

繰り返し可能読み取り分離レベルは、トランザクションが開始する前にコミットされたデータのみを確認し、同時トランザクションによるトランザクション実行中にコミットされていないデータまたはコミットされた変更を確認することはありません。ただし、トランザクションステートメントは、まだコミットされていなくても、自身のトランザクション内で実行された以前の更新の影響を確認します。

異なるノードで実行されているトランザクションの場合、開始とコミットの順序は、タイムスタンプがPDから取得される順序によって異なります。

繰り返し可能読み取り分離レベルのトランザクションは、同じ行を同時に更新することはできません。コミット時に、トランザクションが開始後に別のトランザクションによって行が更新されていることをトランザクションが検出した場合、トランザクションはロールバックします。例えば:

create table t1(id int);
insert into t1 values(0);

start transaction;              |               start transaction;
select * from t1;               |               select * from t1;
update t1 set id=id+1;          |               update t1 set id=id+1; -- In pessimistic transactions, the `update` statement executed later waits for the lock until the transaction holding the lock commits or rolls back and releases the row lock.
commit;                         |
                                |               commit; -- The transaction commit fails and rolls back. Pessimistic transactions can commit successfully.

TiDBとANSIの繰り返し可能な読み取りの違い

TiDBの反復可能読み取り分離レベルはANSI反復可能読み取り分離レベルとは異なりますが、同じ名前を共有しています。 ANSISQL分離レベルの批評のペーパーで説明されている標準に従って、TiDBはスナップショット分離レベルを実装します。この分離レベルでは、厳密なファントム(A3)は許可されませんが、広いファントム(P3)と書き込みスキューは許可されます。対照的に、ANSI反復可能読み取り分離レベルでは、ファントム読み取りは許可されますが、書き込みスキューは許可されません。

TiDBとMySQLの繰り返し可能な読み取りの違い

TiDBのRepeatableRead分離レベルは、MySQLのそれとは異なります。 MySQLのRepeatableRead分離レベルは、更新時に現在のバージョンが表示されているかどうかをチェックしません。つまり、トランザクションの開始後に行が更新された場合でも、更新を続行できます。対照的に、トランザクションの開始後に行が更新された場合、TiDBオプティミスティックトランザクションはロールバックされて再試行されます。 TiDBの楽観的同時実行制御でのトランザクションの再試行が失敗し、トランザクションの最終的な失敗につながる可能性がありますが、TiDBの悲観的同時実行制御とMySQLでは、トランザクションの更新が成功する可能性があります。

コミットされた分離レベルを読み取る

TiDB v4.0.0-ベータ版以降、TiDBはReadCommitted分離レベルをサポートしています。

歴史的な理由から、現在の主流データベースの読み取りコミット分離レベルは基本的にOracleによって定義された一貫性のある読み取り分離レベルです。この状況に適応するために、TiDBペシミスティックトランザクションの読み取りコミット分離レベルも、本質的に一貫した読み取り動作です。

ノート:

読み取りコミット分離レベルは、 悲観的なトランザクションモードでのみ有効です。 楽観的なトランザクションモードでは、トランザクション分離レベルをRead Committedに設定しても有効にならず、トランザクションは引き続き繰り返し可能読み取り分離レベルを使用します。

v6.0.0以降、TiDBは、 tidb_rc_read_check_tsシステム変数を使用して、読み取りと書き込みの競合がまれなシナリオでタイムスタンプの取得を最適化することをサポートしています。この変数を有効にした後、TiDBは、 SELECTが実行されるときに、以前の有効なタイムスタンプを使用してデータを読み取ろうとします。この変数の初期値は、トランザクションのstart_tsです。

  • 読み取りプロセス中にTiDBがデータの更新を検出しなかった場合、TiDBは結果をクライアントに返し、 SELECTステートメントが正常に実行されます。
  • 読み取りプロセス中にTiDBでデータの更新が発生した場合:
    • TiDBがまだ結果をクライアントに送信していない場合、TiDBは新しいタイムスタンプを取得して、このステートメントを再試行します。
    • TiDBがすでに部分的なデータをクライアントに送信している場合、TiDBはクライアントにエラーを報告します。毎回クライアントに送信されるデータの量は、 tidb_init_chunk_sizetidb_max_chunk_sizeによって制御されます。

READ-COMMITTEDの分離レベルが使用されるシナリオでは、 SELECTのステートメントが多く、読み取りと書き込みの競合はまれです。この変数を有効にすると、グローバルタイムスタンプを取得するための遅延とコストを回避できます。

TiDBとMySQLReadCommittedの違い

MySQL Read Committed分離レベルは、ほとんどの場合、一貫性のある読み取り機能と一致しています。 半一貫性のある読み取りなどの例外もあります。この特別な動作は、TiDBではサポートされていません。