ACID特性
ACIDとは?
-
A (Atomicity:原子性)
- トランザクション内の処理はすべて完了するか、まったく行われない(All or Nothing)。
-
C (Consistency:一貫性)
- トランザクション前後でデータの一貫性を保つ。
-
I (Isolation:分離性)
- 複数トランザクションを同時実行しても、相互に影響を受けないようにする。
-
D (Durability:永続性)
- コミットされた変更は障害が起きても失われない。
トランザクション分離レベル
Isolation(分離性) を調整するための仕組みです。
下に行くほど分離レベルが高く、整合性が強化されます。
分離レベル | 特徴 | 発生しうる問題 | デメリット |
---|---|---|---|
Read Uncommitted | 未コミットのデータを読む可能性がある | ダーティリード、ノンリピータブルリード、ファジーリード、ファントムリード | 整合性がほぼ保証されない |
Read Committed | コミット済みデータのみを読み取るため、ダーティリードを防ぐ | ノンリピータブルリード、ファジーリード、ファントムリード | パフォーマンスと整合性のバランスが必要 |
Repeatable Read | 同じトランザクション内で同じ行を読むと、同じ値が返る ノンリピータブルリードを防ぐ |
ファントムリード | ロック範囲が広がり、パフォーマンス低下 |
Serializable | 強制的にトランザクションを直列実行したかのように扱う | 問題なし(すべて防ぐ) | 大量のロックによりスループットが低下 |
不整合の例
1. ダーティリード(Dirty Read)
- 概要: 他のトランザクションが未コミットのデータを読み取ってしまう。
-
例:
- トランザクションA: 顧客の残高を「5000」→「4000」に変更(未コミット)。
- トランザクションB: 未コミットの「4000」を読み取る。
- トランザクションA: ロールバックして残高が「5000」に戻る。
- 結果: トランザクションBは誤った値「4000」を使用してしまう。
- 回避: Read Committed以上を使用。
2. ノンリピータブルリード(Non-Repeatable Read)
- 概要: 同一トランザクション内で同じ行を再度読み取ったときに、他トランザクションの更新によって値が変わる。
-
例:
- トランザクションA: 「顧客ID=1」の残高を読み取る(最初は5000)。
- トランザクションB: 「顧客ID=1」の残高を「6000」に更新しコミット。
- トランザクションA: 再度「顧客ID=1」の残高を読み取る → 今度は「6000」。
- 結果: 1回目と2回目で値が異なる。
- 回避: Repeatable Read以上を使用。
3. ファジーリード(Fuzzy Read)
- 概要: 同じ条件のクエリを複数回実行した際、読み込む行の一部または値が他のトランザクションで更新され、データセット全体が不一致となる。
-
例:
- トランザクションA:
WHERE balance >= 4000
で顧客リストを取得。 - トランザクションB: 既存顧客の残高を変更(例: 5000→3000)してコミット。
- トランザクションA: 再度同じ条件(
WHERE balance >= 4000
)で取得 → 前回とは異なる行が返る可能性。
- 結果: 同じ条件のクエリでも行数や内容が前回とは異なる状態になる。
- トランザクションA:
- 回避: Repeatable Read以上を使用(ただし、ファントムリードほど厳重な対策ではない)。
4. ファントムリード(Phantom Read)
- 概要: 同じ検索条件で再度クエリを実行した際、他のトランザクションによる行の追加・削除で結果行数や集計値が変化する。
-
例:
- トランザクションA:
SELECT SUM(balance)
→1,000,000円
。 - トランザクションB: 新規口座を追加(
100,000円
)してコミット。 - トランザクションA: 再度同じクエリ → 今度は
1,100,000円
。
- 結果: 前回の検索結果とは行数が異なり、「幻の行(Phantom)」が紛れ込む形となる。
- トランザクションA:
- 回避: Serializableを使用。
運用上の注意
-
性能: 分離レベルが高いほどロック競合が増え、スループットが低下する。
- ロック競合: 複数トランザクションが同じデータを同時アクセスする際、整合性を保つために発生する待機やブロック。
- スループット: データベースの処理能力。
- 整合性: 分離レベルが低いほど不正確なデータを読み込むリスクがある。
- 選択基準: 必要なデータ整合性とパフォーマンス要件のバランスを考慮する。
- 通例的なデフォルト: ダティーリードを回避する ReadCommited が使われがち。