【すなっぷしょっとぶんり】

スナップショット分離 とは?

最終更新:
💡 同じ時点の「写真」を見ながら処理するDBの分離方式

トランザクション内の読み取りで、基準時点のコミット済みデータの版を参照する分離方式。他のトランザクションが後から確定した更新は見えず、自分の更新は見える。

📌 このページのポイント
同じ基準時点のデータの版を読む 時点 ① 時点 ② Aが参照する版 残高:100(仮の値) Bの更新が確定 残高:80 Aは引き続き100を読む 自分の更新は見える 同じ行の更新競合では中断もある
AとBは別のトランザクション。読み取りの版の例で、全ロックがなくなることや直列実行の保証ではない。
ひよこ ひよこ
スナップショット分離って、どんな仕組みなの?
ペンギン先生 ペンギン先生
処理中に同じ基準時点のデータの版を読む仕組みだよ。他のトランザクションが後から確定した更新は見えないけれど、自分が行った更新は見える。PostgreSQLでは最初のデータ操作文の開始時点が基準になるよ。
ひよこ ひよこ
じゃあ、同時に別の人が書き込んでいても大丈夫なの?
ペンギン先生 ペンギン先生
通常の読み取りに、更新を止めるための行ロックを使わずに済むので、読み書きの競合を減らせるよ。ただし書き込み同士の待ちや別のロックはあり得る。「全部ロックなし」「必ず高速」ではないんだ。
ひよこ ひよこ
自分が書き込もうとしたときは?
ペンギン先生 ペンギン先生
同じ行を他のトランザクションが更新した場合に、待った後で競合エラーになることがあるよ。中断したら、そのSQLだけでなくトランザクション全体を最初からやり直す。競合を検出する楽観的な方式だけど、アプリで版番号を比較する楽観的ロックと同じ操作ではないよ。
ひよこ ひよこ
普通の分離とどう違うの?
ペンギン先生 ペンギン先生
分離レベルの名前と実装を分けて考えよう。PostgreSQLのRepeatable Readはスナップショット分離で、読み取りに共有行ロックを使う実装とは異なる。SQL ServerではSNAPSHOTを有効化し、使う分離レベルを指定する必要があるよ。
ひよこ ひよこ
じゃあ完璧なの?
ペンギン先生 ペンギン先生
別々の行を変える「書き込みスキュー」で、業務ルールを破ることがあるよ。防ぐにはSerializableを使うか、関係する処理で適切なロックなどを使う設計が必要。Serializableでも競合による中断と再試行はあり得るんだ。
もっと詳しく知りたい人へ

書き込みスキューはどんなときに起こる?

「当番は最低1人」という業務ルールで、AとBが両方とも当番の版を読むとする。別々のトランザクションが相手の当番を確認して自分だけを外すと、異なる行の更新なので両方が確定し、当番が0人になることがある。Serializableを使うか、関係する処理すべてで適切なロック等を使い、ルールを守る設計が必要。中断した場合は処理全体を再試行する。

ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「スナップショット分離」って出てきたら「同じ時点のデータの版を見て処理する分離方式」と思えばだいたいOK!
📖 おまけ:英語の意味
「Snapshot Isolation」 = スナップショット分離
💬 snapshotはある時点の状態、isolationは分離。写真は読み取る版の比喩で、実際にDB全体を複製するとは限らないよ。

参考資料

← 用語集にもどる