明日になったら本気出せる

底辺Web系エンジニアの日記

トランザクション分離レベルについて極力分かりやすく解説してみた[SQL]

トランザクション隔離レベルとか独立性レベルとも呼ばれる。
英語だと Transaction Isolation Level。なんか魔王倒せる直前くらい強そう。
ちょっと前に質問受けた時にすんなり答えられなかったので、極力分かりやすいように意識してまとめてみた。

概要

以下の3つの不都合な読み込み現象がある。この意味に関しては後ほど解説。とりあえずはどれもRDBMSのACID特性のI(Isolation-隔離性)から外れたものと思ってくれればいい。

  • ダーティリード
  • ファジーリード(非再現リード,ノンリピータブルリード)
  • ファントムリード

で、本題のトランザクション隔離レベルは4つのレベルがある。

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

下に行くほど高レベルで上に行くほど低レベル。
高レベルになればなるほど、先ほどの不都合な読み込み現象が発生しなくなる。が、代わりにパフォーマンスが落ちる。

つまり、
「パフォーマンスを上げるためにある程度の読み込み不都合を妥協するか、パフォーマンスを落としてもいいから不都合を発生しないようにするか」
という設定のレベルのことを言う。

読み込みの不都合

ではその3種類の読み込み不都合に関して説明する。

ダーティリード

別のトランザクションでコミットされてないデータが読み取れる現象。

  1. トランザクションAでレコードを①から②にUPDATE(未コミット)
  2. トランザクションBでレコードをSELECTする
  3. トランザクションAをロールバックする
  4. トランザクションBで取得したデータは②となっている。

一番低いレベルでないと発生しない。
これを許容するシステムをまだ見たことがない・・・

ファジーリード(非再現リード,ノンリピータブルリード)

別のトランザクションで更新後データを読むことにより、一貫性がなくなる現象。

  1. トランザクションAでレコードをSELECTする。①となっている。
  2. トランザクションBでレコードを①から②にUPDATEし、COMMITする。
  3. トランザクションAで同じレコードを再度SELECTする。②となっている。

最初RDBMSを触った時これの何がおかしいの?とか思ってた。そういうもんじゃんとか納得してたんだけどよく考えると隔離性としてはおかしいんだよね。

ファントムリード

別のトランザクションで挿入されたデータが見えることにより、一貫性がなくなる現象。

  1. トランザクションAでレコードをSELECTする。該当レコードがない。
  2. トランザクションBでレコードをINSERTし、COMMITする。
  3. トランザクションAでレコードをSELECTする。2でINSERTとしたレコードが取得できる。

ファジーリードとよく似ているがINSERTとUPDATEという点が違う。
また、以下もファントムリードとなる。

  1. トランザクションAでレコードをCOUNTする。X件取得できた。
  2. トランザクションBでレコードをINSERTし、COMMITする。
  3. トランザクションAでレコードをCOUNTする。X+1件取得できた。


以上が読み込みにおける3種類の不都合の簡単な説明となる。

トランザクション分離レベルと読み込みの不都合の関係

簡潔に以下のような関係性となる。

ダーティリード ファジーリード ファントムリード
READ UNCOMMITTED 発生する 発生する 発生する
READ COMMITTED 発生しない 発生する 発生する
REPEATABLE READ 発生しない 発生しない 発生する
SERIALIZABLE 発生しない 発生しない 発生しない

こうしてみると隔離性の高いSERIALIZABLEをいつも選択がいいのではないかと思ってしまうが、隔離性の高さ故の問題もある。が、今回は極力分かりやすくというコンセプトなので説明では省略する。興味があったら調べてみるといいかも。

幾つか重要な補足

  • あくまで「発生しないことが保証されている」というもので、レベル低いからと言って発生するようになっているかと言えばそうとは限らない。その辺りの実装はRDBMSによって大きく違い、例えばMySQLではREPEATABLE READであってもファントムリードは発生しない。
  • 「発生しないことが保証されている」というものなので、発生しない為にどういう方法を取るかというのはRDBMS毎に違う。発生する状況になったらエラーになる、トランザクション完了を待つ等。
  • RDBMSによってデフォルトのトランザクション分離レベルが違う。対応している分離レベルの種類も違う。

デフォルトのトランザクション分離レベル

MySQL(InnoDB) REPEATABLE READ
PostgreSQL READ COMMITTED
Oracle READ COMMITTED
SQL Server READ COMMITTED


何か間違い等あったらご指摘お願いします。