Snapshot isolation

Snapshot isolation（SI、スナップショット アイソレーション）は、データベース管理システムのトランザクション処理において並行動作時のデータの一貫性を保証するためのトランザクションの分離レベルの一種で、次の性質を持つ。
 トランザクションは一貫性のあるデータベースのスナップショット(トランザクション開始時に存在していた最後にコミットされた値)を読む。
 トランザクションの更新がスナップショット以降に他のトランザクションがコミットした更新と競合しない場合に限りトランザクションが成功する。

Snapshot isolation はSQL Anywhere, InterBase, Firebird, Oracle, PostgreSQL, MongoDB, Microsoft SQL Server (2005以降) などの主なデータベース管理システムで採用されている。それはこの分離レベルがSerializable isolationよりも良い性能が実現でき、かつ多くの並列性からくる異常 (anomalies) を回避することができるためである (すべてが回避できるわけではない)。実際にはsnapshot isolationはデータの世代を管理するMultiVersion Concurrency Control (MVCC) の一種として実装される。MVCC は、データベース中のオブジェクトが更新されるたびに新しいバージョンを作成し、並行して実行されているトランザクションのリード操作が他の操作をブロックしないようにすることで、並列性と性能をともに向上させるよく知られた方法である。Snapshot isolation は ANSI SQL-92標準が規定する分離レベルを批判する論文で使用された (snapshot isolation は SQL-92標準が規定する "異常" を一切持たないにもかかわらず、serializable ではない)。

Oracle は snapshot isolation のことを "serializable" と呼んでいるOracle Database Concepts 10g Release 1 (10.1) Chapter 13 : Data Concurrency and Consistency — Oracle Isolation LevelsAsk Tom : On Transaction Isolation LevelsAsk Tom : "Serializable Transaction"。

PostgreSQL は以前は snapshot isolation のことを "serializable" と呼んでいたが、version 9.1 から "repeatable read" と呼ぶよう変更したPostgreSQL 9.0 Documentation: 13.2.2.1. Serializable Isolation versus True SerializabilityPostgreSQL 9.1 press releasePostgreSQL 9.1.14 Documentation: 13.2.3. Serializable Isolation Level。

どちらの判断が正しいかは議論があるが、いずれにせよユーザは両者の違いをよく理解してデータ一貫性を失わないように注意する必要がある。

 動作 
Snapshot isolation の下で実行されるトランザクションは、そのトランザクションの開始時に撮ったスナップショットの上で動作しているように見える。トランザクションが終了すると、そのトランザクションによって行われた更新が、スナップショットを撮った後で発生した他のトランザクションによる更新と衝突しない場合に限って、コミットが成功する。ライト対ライト (write vs write) の衝突が発生すると、トランザクションはアボートする。

ライトスキュー異常 (write skew anomaly) は、2つのトランザクション (T1 と T2) が同時並行的に重複したデータ集合 (V1 と V2 の両方) を読み、それぞれが異なる更新を行い (T1 が V1 を更新し、T2 が V2 を更新)、最後にコミットを行った時に発生する。その際、T1とT2は互いの更新を知ることはないまま、snapshot isolation のシステムではコミットは成功してしまう。しかし serializable isolation のシステムにおいては、T1 と T2 のどちらかが先に実行されたとみなすことができなければならない (一方の更新は他方から見えなければならない) ので、これらはゆるされない。

例えば、V1とV2はある一人の銀行顧客の2つの預金口座の残高であったとする。銀行はこの顧客の預金残高が合計して負にならなければ、一方の残高が負になることを許しているとする (すなわち )。
始め、両方の残高はともに10,000円であったとする。T1 が V1 から 20,000円引き出し、T2 が V2 から 20,000円引き出したらどうなるだろう。

もし、データベースが serializable isolation で動作しているとすると、T1 と T2 をその順序(または逆の順序で)実行するのと等価な結果になるので、T1 は V1 から 20,000円の引き出しに成功し(その時点では が成り立つから)、次に T2 が V2 から 20,000円引き出そうとするが、今度は  が成り立たず、T2 は失敗する。

しかし snapshot isolation においては、T1 と T2 はそれぞれ独自のスナップショットの上で動作するので、両方共がそれぞれ 20,000円を引き出し、合計残高 () が 0円であることを確認し、両者は衝突することなく共に成功してしまう。その結果 円、合計残高 円 となる。

Snapshot isolation が MVCC を用いて実装された場合、トランザクションは並行して行われている操作を心配することなく処理を進めることができ、コミットする際にリード操作を再検証する必要ない。トランザクション実行中に保持しなければならない情報は、更新のリストだけであり、コミット時にはそれを用いて衝突の有無を簡単に確認することができる (衝突が発生していた場合はトランザクションをアボートさせる)。

 関連項目 
 Serializability
 MVCC
 時刻印ロック
 リード・コピー・アップデート

 参考文献 

Category:データベース
Category:トランザクション処理
カテゴリ:並行性制御