トランザクション分離レベル
トランザクション分離レベルとは
[[トランザクションとACID]] の I(独立性)は「あり/なし」の二択ではなく、多くのデータベースで4段階の強さから選べる設定になっています。独立性を強くするほど他のトランザクションから完全に隔離されますが、その分ロック待ちが増え性能は落ちます。「正しさ」と「速さ」のトレードオフを選ぶ仕組みが分離レベルです。
4つのレベル
| レベル | 内容 |
|---|---|
| READ UNCOMMITTED | 他のトランザクションのコミット前の変更まで見えてしまう。最も緩い |
| READ COMMITTED | コミット済みの変更だけが見える。多くのRDBMSの既定値 |
| REPEATABLE READ | 同一トランザクション内は同じ行を何度読んでも同じ値になる |
| SERIALIZABLE | 全トランザクションを1つずつ順番に実行したのと同じ結果を保証する。最も厳格で最も遅い |
起きる3つの読み取り異常
- ダーティリード — 他のトランザクションがまだコミットしていない変更を読んでしまう
- ノンリピータブルリード — 同じ行を2回読む間に、他のトランザクションがコミットして値が変わってしまう
- ファントムリード — 同じ条件で2回検索する間に、他のトランザクションが行を追加・削除して件数が変わってしまう
分離レベルが上がるほど、これらの異常が起きにくくなります。
初学者向けポイント
- 既定値のまま使えばだいたい安全(多くのRDBMSはREAD COMMITTEDが既定)。より厳しくするのは「在庫の二重販売を絶対に防ぎたい」のように整合性が最優先の処理に限る
- 分離レベルを上げるほど [[ロックとデッドロック]] が起きやすくなる。実装によってはロックの代わりに書き込み時の衝突検出でやり直しになる方式(楽観的並行性制御)もある
- 分散環境ではこの独立性の維持コストがさらに増す — [[CAP定理と分散データベース]] の話につながる
関連技術とのつながり
- [[トランザクションとACID]] — 分離レベルはACIDの独立性(I)を具体化する設定
- [[リレーショナルデータベース]] — 分離レベルはDBエンジン・接続単位で設定する
- [[ロックとデッドロック]] — 強い分離レベルほどロック競合が起きやすい
- [[CAP定理と分散データベース]] — 分散環境での整合性保証との関係
- [[分散トランザクションとSaga]] — 1つの処理が複数のDB・サービスにまたがると、そもそもロールバックが届かなくなる
Q: 多くのRDBMSで既定値になっている分離レベルはどれ?
- [ ] READ UNCOMMITTED
- [x] READ COMMITTED
- [ ] SERIALIZABLE
解説: 多くのRDBMSはREAD COMMITTEDを既定値とし、コミット済みの変更だけが見える設定になっています。
Q: 他のトランザクションのコミット前の変更を読んでしまう現象はどれ?
- [x] ダーティリード
- [ ] ノンリピータブルリード
- [ ] ファントムリード
解説: ダーティリードは、まだコミットされていない変更を読んでしまう現象です。
Q: 分離レベルを上げると一般的にどうなる?
- [x] 読み取り異常は減るが、ロック待ちなどにより性能は落ちやすい
- [ ] 読み取り異常は増えるが、性能は上がる
- [ ] 分離レベルは性能に一切影響しない
解説: 独立性を強めるほど他のトランザクションとの干渉を厳しく防ぐため、その分性能とのトレードオフが生じます。