データベースシステムにおいて、分離度はACID(原子性、一貫性、分離性、永続性)トランザクション特性の1つです。これは、トランザクションの整合性が他のユーザーやシステムからどのように見えるかを決定します。分離度が低いほど、多くのユーザーが同時に同じデータにアクセスできる能力は向上しますが、同時に、ユーザーが遭遇する可能性のある同時実行の影響(ダーティリードや更新の消失など)の数も増加します。逆に、分離度が高いほど、ユーザーが遭遇する可能性のある同時実行の影響の種類は減少しますが、より多くのシステムリソースが必要となり、あるトランザクションが別のトランザクションをブロックする可能性が高くなります。[ 1 ]
並行性制御は、 DBMSにおける分離と関連する正当性の保証を処理する基盤となるメカニズムです。データベースエンジンとストレージエンジンは、並行トランザクションの正しい実行を保証するため、また(異なるメカニズムを介して)他のDBMSプロセスの正当性を保証するために、並行性制御を多用します。トランザクション関連のメカニズムは通常、データベースデータアクセス操作のタイミング(トランザクションスケジュール)を、直列化可能性と回復可能性というスケジュール特性で特徴付けられる特定の順序に制限します。データベースアクセス操作の実行を制限すると、通常はパフォーマンス(実行速度で測定)が低下するため、並行性制御メカニズムは通常、制約の下で可能な限り最高のパフォーマンスを提供するように設計されています。多くの場合、正当性を損なわずに可能な場合は、パフォーマンス向上のために直列化可能性特性が犠牲にされます。しかし、回復可能性は犠牲にすることはできません。なぜなら、そのような場合、通常はデータベースの整合性違反が発生するからです。
2フェーズロックは、DBMSにおける最も一般的なトランザクション並行性制御方法であり、シリアライザビリティとリカバリーの両方を提供し、データの正当性を確保するために用いられます。データベースオブジェクトにアクセスするには、トランザクションはまずそのオブジェクトのロックを取得する必要があります。アクセス操作の種類(オブジェクトの読み取りまたは書き込みなど)とロックの種類によっては、別のトランザクションがそのオブジェクトのロックを保持している場合、ロックの取得がブロックされ、延期されることがあります。
分離は通常、データベース レベルで強制されます。ただし、さまざまなクライアント サイド システムも使用できます。J2EEエンティティ ビーンズ[ 2 ]などのアプリケーション フレームワークまたはランタイム コンテナで制御できます。古いシステムでは、一時テーブルの使用などによって、システム的に (アプリケーション開発者によって) 実装される場合があります。2層、3 層、またはn 層のWeb アプリケーションでは、トランザクション マネージャを使用して分離を維持できます。トランザクション マネージャは、アプリケーション サービス (バックエンド アプリケーション サービス) とオペレーティングシステムの間にあるミドルウェアです。トランザクション マネージャは、グローバルな分離とアトミック性を提供できます。トランザクションに新しいサーバーが参加したときを追跡し、サーバー間でアトミック コミットプロトコルを調整します。詳細はアプリケーションから抽象化されているため、トランザクションはよりシンプルでコーディングしやすくなります。トランザクション処理モニタ(TPM) は、トランザクション マネージャを含むミドルウェアの集合です。TPM は、ロック マネージャを使用してアプリケーションにローカルな分離を提供する場合があります。[ 2 ]
ANSI/ISO規格SQL 92では、あるトランザクションが別のトランザクションによって更新された可能性のあるデータを取得する際に発生する、 3つの異なる読み取り現象について言及しています。
以下の例では、2つのトランザクションが実行されます。トランザクション1ではクエリが実行され、トランザクション2では更新が実行され、最後にトランザクション1で同じクエリが再度実行されます。
例では、以下の関係を使用しています。
ダーティリード(未コミット依存関係とも呼ばれる)とは、あるトランザクションが、まだコミットされていない別のトランザクションによって更新された行を取得しようとしたときに発生する現象です。
この例では、トランザクション 1 が ID 1 の行を取得し、次にトランザクション 2 が ID 1 の行を更新し、最後にトランザクション 1 が再び ID 1 の行を取得します。ここで、トランザクション 2 が (トランザクション 1 によって既に取得された) 更新をロールバックしたり、他の更新を実行したりすると、トランザクション 1 での行の表示が間違っている可能性があります。READ UNCOMMITTED 分離レベルでは、トランザクション 1 の 2 番目の SELECT は更新された行を取得します。これはダーティ リードです。READ COMMITTED、REPEATABLE READ、および SERIALIZABLE 分離レベルでは、トランザクション 1 の 2 番目の SELECT は最初の行を取得します。
非反復読み取りとは、トランザクションが同じ行を2回取得し、その間にコミットされた別のトランザクションによってその行が更新される場合に発生します。
この例では、トランザクション 1 が ID 1 の行を取得し、次にトランザクション 2 が ID 1 の行を更新してコミットし、最後にトランザクション 1 が再び ID 1 の行を取得します。READ UNCOMMITTED および READ COMMITTED 分離レベルでは、トランザクション 1 の 2 番目の SELECT は更新された行を取得します。これは非反復読み取りです。REPEATABLE READ および SERIALIZABLE 分離レベルでは、トランザクション 1 の 2 番目の SELECT は最初の行を取得します。
ファントムリードとは、あるトランザクションが同じ行セットを2回取得し、その間にコミットされた別のトランザクションによってその行セットに新しい行が挿入または削除された場合に発生する現象です。
この例では、トランザクション 1 が 17 より大きい行のセットを取得し、次にトランザクション 2 が 26 の行を挿入してコミットし、最後にトランザクション 1 が再び 17 より大きい行のセットを取得します。READ UNCOMMITTED、READ COMMITTED、および REPEATABLE READ 分離レベルでは、トランザクション 1 の 2 番目の SELECT は、挿入された行を含む新しい行のセットを取得します。これはファントム リードです。SERIALIZABLE 分離レベルでは、トランザクション 1 の 2 番目の SELECT は、最初の行のセットを取得します。
非反復読み取りとファントム読み取りを防止するために、2 つの基本的な戦略が用いられます。最初の戦略であるロックベースの並行性制御では、トランザクション 1 がコミットまたはロールバックされた後にトランザクション 2 がコミットされます。これにより、シリアルスケジュールT1、T2が生成されます。もう 1 つの戦略であるマルチバージョン並行性制御では、トランザクション 2 は直ちにコミットされますが、トランザクション 2 より前に開始されたトランザクション 1 は、トランザクション 1 の開始時に取得されたデータベースの古いスナップショットに対して操作を継続します。そして、トランザクション 1 が最終的にコミットを試みたとき、コミットの結果がシリアル スケジュールT1、T2と同等であれば、トランザクション 1 がコミットされます。そうでなければ、コミット競合が発生し、トランザクション 1 はシリアル化エラーでロールバックされます。
ロックベースの同時実行制御では、SELECT の実行時に読み取りロックが取得されない場合、または影響を受ける行に対して取得されたロックが SELECT の実行直後に解放される場合に、非反復読み取りやファントム読み取りが発生する可能性があります。マルチバージョン同時実行制御では、コミット競合の影響を受けたトランザクションをロールバックしなければならないという要件が緩和された場合に、非反復読み取りやファントム読み取りが発生する可能性があります。
データベース管理システム( DBMS )における4つのACID特性のうち、最も頻繁に緩和されるのは分離特性です。最高レベルの分離を維持しようとする場合、DBMSは通常、データにロックを取得するため、並行処理が失われる可能性があり、あるいはマルチバージョン並行制御を実装します。これには、アプリケーションが正しく機能するためのロジックを追加する必要があります。
ほとんどのDBMSは、データ選択時に発生するロックの度合いを制御するトランザクション分離レベルを複数提供しています。多くのデータベースアプリケーションでは、データベーストランザクションの大部分を高い分離レベル(例えばSERIALIZABLEレベル)を必要としないように構築できるため、システムのロックオーバーヘッドを削減できます。プログラマは、データベースアクセスコードを注意深く分析し、分離レベルの緩和によって発見が困難なソフトウェアバグが発生しないようにする必要があります。逆に、より高い分離レベルを使用すると、デッドロックの可能性が高まるため、これもまた、慎重な分析とプログラミング技術によって回避する必要があります。
各分離レベルは下位の分離レベルよりも強力であり、下位の分離レベルで禁止されている操作を上位の分離レベルで許可することはできないため、標準ではDBMSが要求された分離レベルよりも強力な分離レベルでトランザクションを実行することを許可しています(たとえば、「Read committed」トランザクションは実際には「Repeatable read」分離レベルで実行される場合があります)。
ANSI / ISO SQL規格で定義されている絶縁レベルは以下のとおりです。
これは最高レベルの隔離措置です。
ロックベースの並行性制御を採用したDBMSでは、シリアライゼーション性を確保するためには、トランザクションの終了時に(選択されたデータに対して取得された)読み取りロックと書き込みロックを解放する必要があります。また、SELECTクエリで範囲指定のWHERE句を使用する場合は、特にファントムリード現象を回避するために、範囲ロックを取得する必要があります。
ロックを使用しない並行性制御を使用する場合、ロックは取得されません。ただし、システムが複数の同時実行トランザクション間で書き込みの衝突を検出した場合、そのうちの1つだけがコミットを許可されます。このトピックの詳細については、スナップショット分離を参照してください。
出典 : (第 2 次非公式レビュー草案) ISO/IEC 9075:1992、データベース言語 SQL - 1992 年 7 月 30 日: 分離レベル SERIALIZABLE での同時 SQL トランザクションの実行は、シリアル化可能であることが保証されています。シリアル化可能な実行とは、同時実行される SQL トランザクションの操作の実行であり、それらの SQL トランザクションのシリアル実行と同じ効果を生み出すものと定義されます。シリアル実行とは、各 SQL トランザクションが次の SQL トランザクションの開始前に完了するまで実行される実行のことです。
この分離レベルでは、ロックベースの並行性制御を行うDBMSの実装は、トランザクションが終了するまで(選択されたデータに対して取得した)読み取りロックと書き込みロックを保持します。ただし、範囲ロックは管理されないため、ファントムリードが発生する可能性があります。
この分離レベルでは、一部のシステムで書き込みスキューが発生する可能性があります。書き込みスキューとは、2つの異なる書き込み者(更新対象の列を以前に読み取ったことがある)がテーブル内の同じ列に2回書き込みを行うことが許可され、その結果、列に2つのトランザクションのデータが混在する現象です。[ 3 ] [ 4 ]
この分離レベルでは、ロックベースの並行性制御DBMS実装は、トランザクションの終了まで書き込みロック(選択されたデータに対して取得)を保持しますが、読み取りロックはSELECT操作が実行されるとすぐに解放されます(そのため、この分離レベルでは非反復読み取り現象が発生する可能性があります)。前のレベルと同様に、範囲ロックは管理されません。
簡単に言うと、リードコミットとは、読み取られたデータが読み取られた時点でコミットされることを保証する分離レベルです。これは、読み取り側が中間的な、コミットされていない「ダーティ」な読み取りを参照できないように制限するだけです。トランザクションが再度読み取りを実行した場合に同じデータが見つかるという保証は一切ありません。データは読み取り後も変更される可能性があります。
これは最も低い分離レベルです。このレベルでは、ダーティリードが許可されているため、あるトランザクションは、他のトランザクションによって行われたまだコミットされていない変更を参照することができます。
各種DBMSのデフォルトの分離レベルは非常に多様です。トランザクション機能を備えたほとんどのデータベースでは、ユーザーが任意の分離レベルを設定できます。また、一部のDBMSでは、SELECT文を実行する際にロックを取得するために追加の構文が必要になります(例えば、アクセスする行に対して排他書き込みロックを取得するには、 SELECT ... FOR UPDATEを使用します)。
しかしながら、上記の定義は曖昧であり、多くのデータベースが提供する隔離性を正確に反映していないとして批判されている。
ANSI SQLの分離度定義については、実装者が「悪いこと」をするように促すという批判もある。
異常シリアライズ可能はシリアライズ可能と同じではない。つまり、シリアライズ可能なスケジュールが3つの現象タイプすべてから解放されていることは必要条件ではあるが、十分条件ではない。[ 5 ]
(上記ウェブキャストの約 13:30 分を参照!)