「コミットされた読み取り」と「繰り返し可能な読み取り」の違い


245

上記の分離レベルは非常に似ていると思います。誰かがいくつかの良い例を挙げて、主な違いは何ですか?


3
質問を展開し、参照している「分離レベル」(Javaなど)のタグを追加する必要があります。「分離レベル」はややあいまいな用語であり、特定の環境に対する答えを明らかに求めています。
ジェサップ

回答:


564

コミット読み取りは、読み取り時にコミットされたデータが読み取られることを保証する分離レベルです。それは単に、読者が中間のコミットされていない「ダーティー」な読み取りを見るのを制限するだけです。トランザクションが読み取りを再発行した場合に同じデータが見つかるとは限らず、データは読み取られた後に自由に変更できます。

反復可能読み取りはより高い分離レベルであり、コミットされた読み取りレベルの保証に加えて、読み取られたデータが変更されないことも保証します。トランザクションが同じデータを再度読み取る場合、以前に読み取られたデータが変更されていないことがわかります、読み取り可能です。

次の分離レベルであるシリアライズ可能性は、さらに強力な保証を提供します。すべての反復可能な読み取り保証に加えて、後続の読み取りで新しいデータが表示されないことも保証します。

たとえば、列Cが1行のテーブル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分離レベルでは、シリアライズ可能と同じ保証が行われますが、並行トランザクションがデータを変更できないようにする必要はありません。代わりに、すべての読者に独自のバージョンの世界(独自の「スナップショット」)を表示するように強制します。これにより、同時更新をブロックしないため、プログラミングが非常に簡単になるだけでなく、非常にスケーラブルになります。ただし、その利点には代償が伴います。それは、サーバーのリソース消費が増えることです。

補足的な読み取り:


24
上記のREPEATABLE READには間違いがあると思います。既存の行は削除も変更もできないと言っていますが、繰り返し読み取りは実際のデータではなく「スナップショット」を読み取るだけなので、削除または変更できると思います。docsdev.mysql.com/doc/refman/5.0/en/…から:「同じトランザクション内のすべての一貫した読み取りは、最初の読み取りによって確立されたスナップショットを読み取りました。」
デレクリッツ2013年

2
@Derek Litz私はあなたが言っていることのとおりです:トランザクションが行われている間、データはサードパーティから変更できますが、変更は行われなかったかのように、読み取りにはまだ「古い」元のデータが表示されます場所(スナップショット)。
Programster

5
@Cornstalks。はい、ファントム読み取りは削除(または挿入)から発生する可能性があります。はい、ファントムリードは繰り返し可能な読み取りの分離で発生する可能性があります(挿入からのみ)。いいえ、削除からのファントム読み取りは、繰り返し可能な読み取りの分離では発生しません。試して。私が言っていることは、あなたが引用した文書と矛盾していません。
AndyBrown 2014

4
@Cornstalks NP。私自身は100%確信が持てず、誰が正しいのかを確認するために深く掘り下げる必要があったので、私はそれについてまったく言及しませんでした。そして、私は将来の読者が誤解を招くことを望まなかった。コメントを保持します。おそらく、提案されたとおりに保持するのが最善です。そのレベルの細部に興味がある人なら誰でも、すべてのコメントを読むのに十分こだわると確信しています!!
AndyBrown 2014

12
コメントを削除しないでいただきありがとうございます。ディスカッションは、より多くのドットを接続するのに役立ちます。
Josh、

68

繰り返し可能な読み取り

データベースの状態は、トランザクションの開始から維持されます。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

コミットされた読み取り

トランザクションのコンテキスト内では、常に最後にコミットされた値を取得します。session1で値を取得し、session2で更新してから、session1で取得すると、session2で変更された値が取得されます。最後にコミットされた行を読み取ります。

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

理にかなっていますか?


SQL Server 2008で「分離レベルの反復可能読み取りの設定」を使用して反復可能読み取りを試しました。2つのSQLクエリウィンドウを作成しました。しかし、うまくいきませんでした。どうして?
Aditya Bokade 2013

1
なぜ2番目のセッション1がまだAaronを読み上げているのですか?session2のトランザクションは終了してコミットされていませんか?私はこれが古いことを知っていますが、たぶん誰かがいくつかの光を当てることができます。
Sonny Childs、

9
リピータブルリードは、最初のセッションがコミットされるまで2番目のセッションをブロックすると思います。したがって、例は間違っています。
Nighon

4
反復可能読み取りの場合、セッション1が行を読み取ると、共有ロックが設定されます。これにより、(セッション2への)排他ロックが許可されないため、データを更新できません。
Taher

2つのトランザクション間の共有行の更新に関しては、SQLサーバーとMySQLの動作が異なると思います
user2488286

23

このスレッドへの私の読書と理解による単純な答えと@ remus-rusanuの答えは、この単純なシナリオに基づいています。

プロセスAとBの2つがあります。プロセスBはテーブルXを読み取っています。プロセスAはテーブルXに書き込んでいます。プロセスBはテーブルXを再度読み取っています。

  • ReadUncommitted:プロセスBは、プロセスAからコミットされていないデータを読み取ることができ、Bの書き込みに基づいて異なる行を見ることができます。まったくロックなし
  • ReadCommitted:プロセスBはプロセスAからコミットされたデータのみを読み取ることができ、COMMITTEDのみBの書き込みに基づいて異なる行を見ることができます。シンプルロックと呼ぶことができるでしょうか。
  • RepeatableRead:プロセスBは、プロセスAが実行しているすべてのことと同じデータ(行)を読み取ります。ただし、プロセスAは他の行を変更できます。行レベルブロック
  • Serialisable:プロセスBは以前と同じ行を読み取り、プロセスAはテーブルの読み取りまたは書き込みができません。テーブルレベルのブロック
  • スナップショット:すべてのプロセスには独自のコピーがあり、彼らはそれに取り組んでいます。それぞれに独自のビューがあります

15

既に受け入れられている答えを持つ古い質問ですが、SQL Serverのロック動作をどのように変更するかという観点から、これら2つの分離レベルについて考えたいと思います。これは、私と同じようにデッドロックをデバッグしている人に役立つかもしれません。

READ COMMITTED(デフォルト)

共有ロックはSELECTで取得され、SELECTステートメントが完了すると解放されます。これは、コミットされていないデータのダーティリードがないことをシステムが保証する方法です。SELECTが完了した後、トランザクションが完了する前に、他のトランザクションが基になる行を変更する可能性があります。

反復可能な読み取り

共有ロックはSELECTで取得され、トランザクションの完了後にのみ解放されます。これは、トランザクション中に読み取った値が変更されないことをシステムが保証できる方法です(トランザクションが完了するまでロックされたままであるため)。


13

この疑問を簡単な図で説明しようとしています。

コミット読み取り:この分離レベルでは、トランザクションT1はトランザクションT2によってコミットされたXの更新された値を読み取ります。

コミットされた読み取り

反復可能読み取り:この分離レベルでは、トランザクションT1はトランザクションT2によってコミットされた変更を考慮しません。

ここに画像の説明を入力してください



0

、それを注意してください、反復タプルに、全体ではなく、テーブルに反復可能読み取りに関してインチ ANSC分離レベルでは、幻像読み取り異常が発生する可能性があります。つまり、同じwhere句を使用してテーブルを2回読み取ると、異なる結果セットが返される場合があります。文字通り、それは再現可能ではありません。


-1

最初に受け入れられた解決策についての私の観察。

RRの下(デフォルトのmysql)-txが開いていて、SELECTが起動された場合、別のtxは、前のtxがコミットされるまで、以前のREAD結果セットに属する行を削除できません(実際には、新しいtxのdeleteステートメントがハングするだけです)。ただし、次のtxは問題なくテーブルからすべての行を削除できます。ところで、以前のtxの次のREADでは、コミットされるまで古いデータが表示されます。


2
あなたはそれをコメント欄に入れて、回答者が通知を受けるようにすることができます。そうすれば、彼はあなたの観察に応答し、必要に応じて修正を加えることができます。
RBT 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.