行のバージョン管理に基づく分離レベルの選択
行のバージョン管理に基づく分離レベルを使用すると、読み取り操作でのロックが排除され、読み取りの同時実行性が向上します。MicrosoftSQL Server には、行のバージョン管理を使用する次の 2 つのトランザクション分離レベルが導入されています。
READ COMMITTED 分離の新しい実装。READ_COMMITTED_SNAPSHOT データベース オプションが ON の場合に行のバージョン管理を使用します。
新しい分離レベルである "スナップショット"。ALLOW_SNAPSHOT_ISOLATION が ON の場合に有効です。
次の理由により、ほとんどのアプリケーションでは、スナップショット分離よりも、行のバージョン管理を使用する READ COMMITTED 分離が推奨されます。
READ COMMITTED 分離では、スナップショット分離ほど tempdb の領域が使用されません。
READ COMMITTED 分離は分散トランザクションで使用できます。一方、スナップショット分離は分散トランザクションでは使用できません。
READ COMMITTED 分離はほとんどの既存のアプリケーションでアプリケーションを変更することなく使用できます。既定の分離レベルである READ COMMITTED を使用して記述されたアプリケーションは、動的にチューニングすることができます。READ COMMITTED の動作は、行のバージョン管理を使用するかどうかに関係なくデータベース オプションの設定によって決まります。また、アプリケーションに影響を与えることなく動作を変更できます。
注意 READ COMMITTED 分離のブロッキング動作に依存するようにデザインされているアプリケーションの場合、開発者はそのアプリケーションを READ COMMITTED 分離のどちらのモードでも機能するように変更できます。それ以外のアプリケーションの場合は、READ_COMMITTED_SNAPSHOT データベース オプションを OFF のままにしておくことが重要です。
スナップショット分離は更新の競合が発生しやすいのですが、行のバージョン管理を使用する READ COMMITTED 分離は違います。スナップショット分離レベルで実行されているトランザクションで別のトランザクションによって後で変更されるデータを読み取る場合、そのスナップショット トランザクションで同じデータを変更しようとすると更新の競合が発生し、そのトランザクションは終了してロールバックされます。この問題は、行のバージョン管理を使用する READ COMMITTED 分離には関係ありません。
行のバージョン管理を伴う READ COMMITTED 分離の使用
行のバージョン管理を伴う READ COMMITTED 分離を使用すると、一貫性を保った状態でステートメントレベルの読み取り操作を実行できます。トランザクション内の各ステートメントの実行時に新しいデータ スナップショットが作成されるので、各ステートメントの一貫性がそのステートメントの実行が終了するまで維持されます。行のバージョン管理を伴う READ COMMITTED 分離は、次のような場合に有効にします。
行バージョンの作成および管理のオーバーヘッドが増加するという欠点よりも、同時実行の利点の方が上回った時点で、リーダーとライタのブロッキングが発生する場合。
アプリケーションが、実行時間の長い集計またはクエリに完全な正確性を求める場合。クエリの開始時までデータ値の一貫性が維持されている必要があります。
スナップショット分離を使用する場合
スナップショット分離を使用すると、一貫性を保った状態でトランザクションレベルの読み取り操作を実行できます。スナップショット トランザクションを開始するとデータ スナップショットが作成され、トランザクションを実行している間、一貫性が維持されます。スナップショット分離は、次のような場合に使用します。
オプティミスティック同時実行制御が適している場合。
更新の競合によりトランザクションのロールバックが必要になる可能性が低い場合。
アプリケーションで、実行時間の長い、特定の時点での一貫性が必要な、複数のステートメントを使用したクエリに基づきレポートを生成する必要がある場合。スナップショット分離は、共有ロックを使用せずに REPEATABLE READ の利点を提供します (詳細については、同時実行の影響 を参照してください)。データベース スナップショットでも同様の機能を使用できますが、手動でその機能を実装する必要があります。スナップショット分離では、スナップショット分離トランザクションごとにデータベース内の最新の情報が自動的に提供されます。
行のバージョン管理に基づく分離レベルの利点
行のバージョン管理を使用する分離レベルには次の利点があります。
読み取り操作では、一貫性のあるデータベースのスナップショットが取得されます。
SELECT ステートメントでは、読み取り操作の間データがロックされません (リーダーはライタをブロックせず、その逆も同様です)。
他のトランザクションによってブロックを伴わずに行が更新されている間、SELECT ステートメントを使用してその行の最後にコミットされた値にアクセスできます。
デッドロックの数が減ります。
トランザクションによって要求されるロック数が減るので、ロックの管理に必要なシステム オーバーヘッドも減ります。
ロックのエスカレーションの発生を抑えられます。
行のバージョン管理に基づく分離レベルのコスト
行のバージョン管理に基づく分離を使用する場合は、行バージョンの管理と読み取りに必要なリソース使用量が増加する欠点よりも、ロックを最小限に抑えるという同時実行の利点の方が上回っている必要があります。スナップショット分離レベルおよび READ COMMITTED 分離レベルに対して行のバージョン管理を有効にする場合は、次の関連コストを検討してください。
クエリに必要なバージョンが古くなり、長いバージョン チェーンをスキャンする必要がある場合、読み取り操作のパフォーマンスが影響を受ける可能性があります。
行のバージョン管理では、データの変更中、tempdb で管理される行バージョンと同じ量だけリソースの使用量が増加します。
READ_COMMITTED_SNAPSHOT データベース オプションまたは ALLOW_SNAPSHOT_ISOLATION データベース オプションのいずれかが ON の場合、行のバージョン管理に基づく分離レベルを使用するトランザクションが存在しない場合でも、特定のデータベースに対する更新トランザクションおよび削除トランザクションでは行バージョンを維持する必要があります。一貫性のあるデータのスナップショットを行バージョンを使用して作成するには、システム リソース (CPU およびメモリ) と、場合によっては I/O 操作が必要です。レコード バージョンは tempdb に格納されるので、行バージョン管理用のメモリに格納できる tempdb ページが多いほど、パフォーマンスが高くなり I/O 操作の回数が少なくなります。
注意 通常、行の挿入では行バージョンは生成されません。ただし、ある条件下では、INSERT コマンドにより行バージョンが生成されます。たとえば、以前削除された行バージョン (非実体レコード) が切り捨てられていない場合に一意インデックスを持つテーブルに行を挿入すると、INSERT コマンドにより行バージョンが生成されます。
tempdb には、バージョン ストア用の十分なディスク領域が必要です。非常に実行時間の長いトランザクションが存在する場合、更新トランザクションの実行中、その更新トランザクションによって生成されたすべてのバージョンを tempdb で維持する必要があります。tempdb の領域が不足すると、更新操作は成功しますが、行のバージョン管理を使用する読み取り操作は失敗する場合があります。
行のバージョン管理情報には、データベース行に 14 バイトの追加が必要になります。
行バージョンの管理に伴う処理により、更新のパフォーマンスが低下する場合があります。一般的な OLTP ワークロードでは、各更新操作により変更されるデータベース内の行は数行だけです。このようなシステムでは、行のバージョン管理オプションを ON にしたデータベースでの更新パフォーマンスの低下は、両方のオプションを OFF にしたデータベースと比べても、わずか数パーセントにとどまると考えられます。更新操作中に変更されるデータ量が多いほど、バージョン管理された更新のパフォーマンス コストは高くなります。
データ リーダーに対して、バージョン リンク リストを移動する追加コストを考慮する必要があります。スナップショット分離トランザクションでは、スナップショットが古いほどバージョン リンク リストへのアクセス処理が遅くなります。
更新操作に対する強制競合検出が原因で、スナップショット分離を使用する一部の更新トランザクションをロールバックすることが必要になる場合があります。行のバージョン管理を使用した READ COMMITTED 分離レベルで実行しているトランザクションでは、更新の競合は発生しません。
行のバージョン管理を使用したトランザクションにはその他の制限事項があります。詳細については、「行のバージョン管理に基づく分離レベルの使用」を参照してください。
行のバージョン管理に基づく分離レベルから利点を得られるシステム
次のような場合に、行のバージョン管理に基づく分離レベルの利点が得られます。
読み取り専用のレポートとアドホック クエリが、それらのデータを更新しているアプリケーションと並行して実行されるシステムの場合。
同様の分離レベルをサポートしている他のリレーショナル データベース システムから MicrosoftSQL Server データベース エンジンにアプリケーションを移行する場合。
AVG、COUNT、SUM などの一貫性のある集計を取得するシステム、またはインデックス積集合およびインデックス結合を実行しているシステムで、厳密な分離レベル (REPEATABLE READ や SERIALIZABLE など) が必要とされる場合。
読み取りと書き込みの競合によりデッドロックの数が非常に多いシステムの場合。