上記の分離レベルは非常に似ていると思います。主な違いは何ですか?
8 に答える
コミットされた読み取りは、読み取り時にコミットされたデータが読み取られることを保証する分離レベルです。それは単に、読者が中間の、コミットされていない、「ダーティ」な読み取りを見るのを制限するだけです。トランザクションが読み取りを再発行し、同じデータが検出された場合、データは読み取り後に自由に変更できることを約束するものではありません。
繰り返し可能な読み取りは、より高い分離レベルであり、読み取りコミットレベルの保証に加えて、データの読み取りが変更されないことも保証します。トランザクションが同じデータを再度読み取ると、以前に読み取られたデータが変更されずに配置されます。 、および読むことができます。
次の分離レベルであるシリアライズ可能は、さらに強力な保証を行います。繰り返し可能な読み取りの保証に加えて、後続の読み取りで新しいデータが表示されないことも保証します。
1つの行を含む列Cを持つテーブルTがあり、値が「1」であるとします。そして、次のような単純なタスクがあると考えてください。
BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;
これは、テーブルTから2つの読み取りを発行する単純なタスクであり、それらの間に1分の遅延があります。
- READ COMMITTEDでは、2番目のSELECTが任意のデータを返す場合があります。並行トランザクションは、レコードの更新、削除、新しいレコードの挿入を行う場合があります。2番目の選択では、常に新しいデータが表示されます。
- REPEATABLE READでは、2番目のSELECTは、少なくとも最初のSELECTから返された行を変更せずに表示することが保証されています。その1分間の同時トランザクションによって新しい行が追加される場合がありますが、既存の行を削除または変更することはできません。
- SERIALIZABLE読み取りの下で、2番目の選択は最初の選択とまったく同じ行を表示することが保証されています。同時トランザクションによって行を変更したり、削除したり、新しい行を挿入したりすることはできません。
上記のロジックに従うと、SERIALIZABLEトランザクションは簡単になりますが、行を変更、削除、挿入する必要がないため、可能なすべての同時操作を常に完全にブロックしていることがすぐにわかります。.Netスコープのデフォルトのトランザクション分離レベルSystem.Transactions
はシリアル化可能であり、これは通常、結果として生じるひどいパフォーマンスを説明します。
そして最後に、SNAPSHOT分離レベルもあります。SNAPSHOT分離レベルは、シリアル化可能と同じ保証を行いますが、同時トランザクションがデータを変更できないことを要求することによってではありません。代わりに、すべての読者に独自のバージョンの世界を表示するように強制します(独自の「スナップショット」)。これにより、同時更新をブロックしないため、プログラミングが非常に簡単になり、スケーラブルになります。ただし、そのメリットには代償が伴います。つまり、サーバーリソースの消費が増えます。
補足資料:
反復可能な読み取り
データベースの状態は、トランザクションの開始から維持されます。session1 で値を取得し、session2 でその値を更新すると、session1 で再度取得しても同じ結果が返されます。読み取りは繰り返し可能です。
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
コミットされた読み取り
トランザクションのコンテキスト内では、常に最後にコミットされた値を取得します。セッション 1 で値を取得し、それをセッション 2 で更新してから、セッション 1 で再度取得すると、セッション 2 で変更された値が取得されます。最後にコミットされた行を読み取ります。
session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;
session1> SELECT firstname FROM names WHERE id = 7;
Bob
理にかなっていますか?
このスレッドと@remus-rusanuの回答を読んで理解した回答は、次の単純なシナリオに基づいています。
2 つのトランザクション A と B があります。トランザクション B はテーブル X を読み取ります。トランザクション A はテーブル X に書き込みます。トランザクション B はテーブル X を再度読み取ります。
- ReadUncommitted : トランザクション B は、トランザクション A からコミットされていないデータを読み取ることができ、B の書き込みに基づいて別の行を見ることができます。全然ロックしない
- ReadCommitted : トランザクション B は、トランザクション A からコミットされたデータのみを読み取ることができ、COMMITTED のみの B 書き込みに基づいて異なる行を表示できます。シンプルロックと呼べるでしょうか?
- RepeatableRead : トランザクション B は、トランザクション A が行っていることと同じデータ (行) を読み取ります。ただし、トランザクション A は他の行を変更できます。行レベル ブロック
- Serialisable : トランザクション B は以前と同じ行を読み取り、トランザクション A はテーブルの読み取りまたは書き込みを行うことができません。テーブルレベル ブロック
- スナップショット: すべてのトランザクションには独自のコピーがあり、そのコピーに取り組んでいます。それぞれに独自のビューがあります
すでに回答が受け入れられている古い質問ですが、SQL Server のロック動作をどのように変更するかという観点から、これら 2 つの分離レベルを考えたいと思います。これは、私のようにデッドロックをデバッグしている人にとっては役立つかもしれません。
READ COMMITTED (デフォルト)
共有ロックは SELECT で取得され、SELECT ステートメントが完了すると解放されます。これは、コミットされていないデータのダーティ リードがないことをシステムが保証できる方法です。SELECT が完了した後、トランザクションが完了する前に、他のトランザクションが基礎となる行を変更する可能性があります。
反復可能な読み取り
共有ロックは SELECT で取得され、トランザクションが完了した後にのみ解放されます。これにより、システムは、読み取った値がトランザクション中に変更されないことを保証できます (トランザクションが終了するまで値がロックされたままになるため)。
最初に受け入れられた解決策に関する私の観察。
RR の下 (デフォルトの mysql) - tx が開いていて SELECT が起動されている場合、別の tx は、前の tx がコミットされるまで、前の READ 結果セットに属する行を削除できません (実際、新しい tx の delete ステートメントはハングします)。 、ただし、次の tx は問題なくテーブルからすべての行を削除できます。ところで、前の tx の次の READ では、コミットされるまで古いデータが表示されます。