この記事のオリジナルは、Glenn Paulley が sybase.com に 2009 年 5 月に掲載したものです。その中で、Glenn は MVCC とスナップショットアイソレーション (これは SAP HANAの一部にもなりました) について語るとともに、同時アクセスユーザーの数が増加していく中で一定レベルのパフォーマンスを提供するためにはこれがたいへん便利である理由について解説しています。
多くの商用およびオープンソースのデータベース管理システム、例えば Microsoft SQL Server、Oracle、MySQL (InnoDB または Falcon ストレージエンジン)、PostgreSQL、Firebird、H2、Interbase、Sybase IQ、そして
SQL Anywhere では、短縮してMVCC またはスナップショットアイソレーションと呼ばれることも多いマルチバージョンによるトランザクションの同時実行をサポートしています。
なぜ、スナップショットアイソレーションのサポートがこれほどまでに重要なのでしょうか ? それは、スナップショットアイソレーションが、直列化可能なクエリ実行戦略の順序制御や相当な量のオーバーヘッドを発生させることなく、様々なタイプの更新処理における競合や例外の回避において理に適った構造を提供するという、データベース管理者の選択肢の一つとなるからです。
「selializability」 という単語は、データベースに接続している複数のアプリケーションが発行するコマンドが直列化されシリアルに(一つずつ)実行されたかのような実行スケジュールの特長を表しています。最初に下で参照している[1] に掲載され、その後Oracleに実装されたスナップショットアイソレーションのアイディアより以前は、直列化したトランザクションを使用して複数のトランザクションを同時に実行する方法は、厳密なツーフェーズロックを通じて行う方法で、大変高コストでした。大多数のデータベースアプリケーションでは、必要とされる同時実行性の欠如に耐えられませんでした。ほとんど全てのケースで、アプリケーション開発者は、強いトランザクション分離レベルによる処理の一貫性の確保と、弱いトランザクション分離レベルによる同時実行性の確保を天秤にかけ、後者を選択する傾向があります。そのため、これらを両立させ、より弱いトランザクション分離レベルによる同時実行性をコントロールするためにスナップショットアイソレーションが重要なのです。
ANSI/ISO 標準 SQL は、回避した方が良い可能性のあるトランザクションに発生する例外現象に関して分離レベルを定義しています。 (SQL:2008, Section 4.35.4, pp. 124-5):
この分離レベルは、同時にSQL トランザクションを実行している間に発生する現象の種類を特定します。以下の現象の可能性があります。
- P1 ("Dirty read"): SQL-トランザクション T1 は、行を修正します。SQL-トランザクション T2 は T1 が
COMMIT
を実行する前に行を読み込みます。T1 が、ROLLBACK
を実行した場合には、T2 はコミットされていない行を読んだことになり、それゆえ存在しなかったと考えられる可能性があります。
- P2 ("Non-repeatable read"): SQL-トランザクション T1 は行を読み込みます。SQL-トランザクション T2 はその行を修正または削除し、
COMMIT
を実行します。 T1 が行の読み込みを試みると、修正された値を受け取るか、または、削除された行を発見する可能性があります。
- P3 ("Phantom"): SQL-トランザクション T1 がある検索条件を満たす行のセット N を読み込みます。SQL トランザクション T2 は、SQL-トランザクションT1に使用された検索条件を満たす 一つ以上の行を生成する SQL 文を実行します。SQL-トランザクション T1 は、同じ検索条件の最初の読み込みを繰り返し、異なる行の集合を得えます。
上の定義は、SERIALIZABLE よりも弱い分離レベルの際に起こる例外事象の全てを網羅していないということがよく知られています[1]。 データベース管理者とアプリケーションプログラマーなどが、低い分離レベルで起こる可能性のある例外事象の動作を理解したい場合には、Berenson et al.による論文 [1] を推奨します。しかしながら、ANSI 分離レベル 1 から 3 の共通の性格として、writer が reader をブロックするということがあります。他の多くの DBMS の実装と同様に、SQL Anywhereの同時実行性制御は、ロッキングに基づいており、正確性の保証のない分離レベル 0 (READ UNCOMMITTED) を提供するアイソレーションレベルにおける read トランザクションを除いて、書き込みロックはブロッキングを発生させます。さらに、writers は常に他の writers をブロックします。SQL Anywhere は、 - どの分離レベルでも、- [1] においてP0と定義されている - dirty writes が許可されている場合に発生する
ROLLBACK
とリカバリーの問題があるため、「dirty write」は許可していません。
標準 SQL では、これらの P1、P2、P3 の例外の回避方法については特定していません。そのため各々のデータベース管理システムは、自由に独自のソリューションを実装することができます。例えば、SQL Anywhere の Version 10 からは、更新による競合を回避するために、インテントロックとupdate-ableカーソルを利用しています。インテントロックは、少なくとも、行が実際に修正され、インテントロックが書き込みロックにアップグレードされるまでは、読み込みトランザクションを許可し、行を処理します。
ANSI アイソレーションレベルの拡大に追加して、参考 [1] では
スナップショットアイソレーションが定義されています。基本的な考え方は、それぞれのトランザクションがトランザクションが開始した時点におけるデータベースの一貫したスナップショットを「見る」ためであり、このスナップショットが、他の同時に行われる更新トランザクションによって影響を受けないようにすることです。用語のいたずらで、多くの人は、スナップショットアイソレーションは、直列化可能な構造を実現するものと信じています。しかしながら、スナップアイソレーションでは、直列化は
できません [3]。そのため、何人かの研究者が、何年にもわたって、直列化できるようスナップショットアイソレーションの修正を提案してきました。 [4]
[1] で提案され、Oracle に実装されたスナップショットアイソレーションは、
first-committer-wins に基づいています。つまり、二つのトランザクションが同じローを更新する場合に、これはこのスキームで許可されており、最初に
COMMIT
するトランザクションが「win」します。 そして、競合しているもう一つのトランザクションは
COMMIT
できず、
ROLLBACK
しなければなりません。対照的に、SQL Anywhere におけるスナップショットアイソレーションは、
first-writer-wins に基づいており、writers に対して writers をブロックするよう強要します。これによって、アプリケーションの
COMMIT
ロジックをシンプルにすることができるというメリットがありますが、デッドロックになりやすいという大きなリスクのデメリットもあります。しかしながら、SQL Anywhere のスナップショットアイソレーションは、writer が reader をブロックしないというメリットを維持しているため、アプリケーションは、そのデータベースがトランザクションを開始して以降一貫性を保った状態であることを「見る」ことができます。簡潔に言うと、例えば、read-only のトランザクションが、同じく実行中の他のトランザクションによって行われた更新処理に関係なく、データベース全体を分析することができます。これは、スナップショットアイソレーションのとても強力なメリットです。
もちろん、スナップショットアイソレーションは「タダ」ではありません。データベースシステムは、新たなスナップショットトランザクションを予期して、変更されたデータのアーカイブコピーを構築することが必要です。SQL Anywhere では、スナップショット行のコピーは、自動的に管理されており、必要に応じて (オンデマンドで拡大する) temp ファイルに書き込まれます。しかしながら、管理のインパクトはほとんどゼロとはいえ、クエリのパフォーマンスに苦しむ可能がないわけではありません。なぜならば、スナップショット行を、そのトランザクションのスナップショットセマンティクスに基づき、temp ファイルのスナップショット行ストアから別々にフェッチする必要がある可能性があるからです。パフォーマン低下の程度は、アプリケーションとそのワークロードに依存し、特に更新が集中するワークロードでは、さらに低下します。このような同じ更新が集中するワークロードは、一般的な ANSI 分離レベルでは、ロックコンテンションが発生する可能性があるため、うまく機能しない可能性があり、また、デッドロックが発生する潜在的な可能性は大きくなります。そのため、注意深く容量計画を立てる必要があります(tempファイルを多く使用することになるので、ディスクの容量に注意する必要があります)。
NB. Links to papers are to freely available, public preprint versions.
[1] Hal Berenson, Phil Bernstein, Jim Gray, Jim Melton, Elizabeth O'Neil, and Patrick O'Neil (June 1995). A Critique of ANSI SQL Isolation Levels. Proceedings of the 1995 ACM SIGMOD Conference, San Jose, California, pp. 1-10. Also available as Microsoft Research Technical Report MSR-TR-95-51.
[2] Atul Adya, Barbara Liskov, and Patrick O'Neil (March 2000). Generalized Isolation Level Definitions. In Proceedings of the 2000 IEEE International Conference on Data Engineering, San Diego, California, pp. 67-78.
[3] Alan Fekete, Elizabeth O'Neil, and Patrick O'Neil (September 2004). A Read-only Transaction Anomaly Under Snapshot Isolation. ACM SIGMOD Record 33(3), pp. 12-14.
[4] Alan Fekete, Dimitrios Liarokapis, Elizabeth O'Neil, Patrick O'Neil, and Dennis Shasha (June 2005). Making snapshot isolation serializable. ACM Transactions on Database Systems 30(2), pp. 492-528.