Transaction isolation level
トランザクション分離レベル
複数のtransactionの相互作用を制御する
複数のtransactionが同時に動くときに、お互いの読み書きをどこまで隔離するかを決定する
性能と整合性のトレードオフがあるので、それを調整するということ
Isolation Level が低いと
同時実行性能が高い
ただし、読み取りの不整合が起こり得る
Isolation Level が高いと
データの整合性は強い
ただし、ロックや待ちが増え性能が下がる
#wip
先に、そもそもどういう不整合が起きるのか?を抑えていると、各Levelの意義を理解しやすい
分離レベルごとに起こる典型的な不整合の例
Dirty Read
Non-repeatable Read
Phantom Read
Write Skew
https://qiita.com/kumagi/items/5ef5e404546736ebac49
AnomalyとはSerializableでない実行を引き起こす異常状態パターンのことを言う。
Dirty Read
Read Skew
Lost Update
Inconsistent Read
Write Skew
Read Only Anomaly
標準的な4種類の Isolation Level
以下は ANSI SQL の4段階
(実際には DB 実装によって挙動がずれることがある)
table:_
Isolation Level \ 典型的な不整合 Dirty Read Non-repeatable Read Phantom Read Write Skew
①READ UNCOMMITTED ❌ ❌ ❌ ❌
②READ COMMITTED ✅ ❌ ❌ ❌
③REPEATABLE READ ✅ ✅ △(MySQLはほぼ防ぐ) ❌
④SERIALIZABLE ✅ ✅ ✅ ✅
下に行くほど厳しい
つまり不整合は起きづらくなる
が、性能は低くなる
https://qiita.com/song_ss/items/38e514b05e9dabae3bdb
https://www.kimullaa.com/entry/2020/03/14/134232
https://speakerdeck.com/soudai/webenzinianizhi-tutehosiirdbantipatan?slide=78
https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html
mysql
gpt-5.icon
🔍 4. DBごとの挙動の違い(重要)
DB実装ごとに Isolation Level の内部動作が違う点は非常に重要。
table:_
DB デフォルト 特記事項
PostgreSQL READ COMMITTED SERIALIZABLE は SSI(Serializable Snapshot Isolation)で実現
MySQL InnoDB REPEATABLE READ MVCCが強力で Phantom Read を防ぐ(実質 Serializable寄り)
Oracle READ COMMITTED 実装は独自(Snapshot based)
特に MySQL InnoDB の REPEATABLE READ は ANSI と挙動が違うというのはポイント。
💡 6. 実務での使い分け
WebアプリやAPIサーバーの通常業務なら、ほとんどは:
READ COMMITTED(Postgres)
REPEATABLE READ(MySQL/InnoDB)
で十分です。
実務的なTips
🔹 大量読み取りAPI → READ COMMITTED で十分
レポート生成・一覧表示などでは厳密な一貫性は不要。
🔹 会計・決済などの整合性が死ぬほど重要 → SERIALIZABLE
銀行・株取引・金額系の二重処理など。
🔹 「2つの値の整合性が崩れるとまずい」 → SERIALIZABLE or アプリ側でロック
Write Skew が起きる可能性があるケース
(例:医者が同時にオンコール登録を更新して0人になる、など)
🔹 競合が多い場合 → SERIALIZABLE は Retry が頻発
アプリ側リトライ(再実行)を実装する必要あり
✏️ 7. 例:Write Skew の具体例
病院当番の例。
code:_
Tx1:
SELECT COUNT(*) FROM doctors WHERE oncall = true; → 1
(誰か他にいるだろうと判断)
UPDATE doctors SET oncall = false WHERE id = 1;
Tx2:
SELECT COUNT(*) FROM doctors WHERE oncall = true; → 1
UPDATE doctors SET oncall = false WHERE id = 2;
結果:on-call 医師が0人になる。
これは
REPEATABLE READ でも起こる(PostgreSQL / MySQL)
SERIALIZABLE なら防げる