コンテナー間トランザクションは、ネイティブ コンパイル ストアド プロシージャの呼び出しやメモリ最適化テーブルに対する操作を含む、暗黙的または明示的なユーザー トランザクションです。
SQL Server では、ストアド プロシージャの呼び出しはトランザクションを開始しません。 (ユーザー トランザクションのコンテキストではなく) 自動コミット モードでのネイティブ コンパイル プロシージャの実行は、コンテナー間トランザクションとは見なされません。
メモリ最適化テーブルを参照する解釈されたクエリは、明示的または暗黙的なトランザクションから実行されるか、自動コミット モードで実行されるかに関係なく、コンテナー間トランザクションの一部と見なされます。
個々の操作の分離
各 SQL Server トランザクションには分離レベルがあります。 既定の分離レベルは Read Committed です。 別の分離レベルを使用するには、 SET TRANSACTION ISOLATION LEVEL (Transact-SQL) を使用して分離レベルを設定できます。
多くの場合、ディスク ベースのテーブルに対する操作とは異なる分離レベルで、メモリ最適化テーブルに対して操作を実行する必要があります。 トランザクションでは、ステートメントのコレクションまたは個々の読み取り操作に対して異なる分離レベルを設定できます。
個々の操作の分離レベルの指定
トランザクション内のステートメントのセットに対して異なる分離レベルを設定するには、 SET TRANSACTION ISOLATION LEVEL
を使用できます。 次のトランザクションの例では、シリアル化可能な分離レベルが既定として使用されます。 t3、t2、および t1 に対する挿入操作と選択操作は、反復可能な読み取り分離の下で実行されます。
set transaction isolation level serializable
go
begin transaction
......
set transaction isolation level repeatable read
insert t3 select * from t1 join t2 on t1.id=t2.id
set transaction isolation level serializable
......
commit
トランザクションの既定値とは異なる個々の読み取り操作の分離レベルを設定するには、テーブル ヒント (シリアル化可能など) を使用できます。 行は常に更新または削除する前に読み取る必要があるため、すべての選択は読み取り操作に対応し、すべての更新とすべての削除は読み取りに対応します。 SQL Server では書き込みが常に分離されるため、挿入操作には分離レベルがありません。 次の例では、トランザクションの既定の分離レベルは読み取りコミットされますが、テーブル t1 はシリアル化可能な状態でアクセスされ、t2 はスナップショット分離の下でアクセスされます。
set transaction isolation level read committed
go
begin transaction
......
insert t3 select * from t1 (serializable) join t2 (snapshot) on t1.id=t2.id
......
commit
個々の操作の分離セマンティクス
シリアル化可能なトランザクション T は、完全に分離して実行されます。 これは、他のすべてのトランザクションが T が開始される前にコミットされたか、T がコミットされた後に開始されたかのいずれかであるかのように表示されます。 トランザクション内の操作によって分離レベルが異なると、より複雑になります。
SQL Server のトランザクション分離レベルの一般的なセマンティクスとロックへの影響については、「 SET TRANSACTION ISOLATION LEVEL (Transact-SQL)」で説明します。
異なる操作で分離レベルが異なる可能性があるコンテナー間トランザクションの場合は、個々の読み取り操作の分離のセマンティクスを理解する必要があります。 書き込み操作は常に分離されます。 異なるトランザクションでの書き込みは、互いに影響を与えることはできません。
データ読み取り操作では、フィルター条件を満たす多数の行が返されます。
読み取りはトランザクション T の一部として実行されます。読み取り操作の分離レベルは、
コミットの状態
コミットの状態とは、読み取られたデータが確実にコミットされるかどうかを示します。
(トランザクション)一貫性
一連の読み取りのトランザクション整合性とは、読み取られた行バージョンがすべて、まったく同じトランザクション セットからの更新を含むように保証されるかどうかを指します。
安定性は、システムが読み取られたデータに関するトランザクション T に与える保証をします。
安定性とは、トランザクションの読み取りを繰り返し可能にするかどうかを指します。 つまり、読み取りが繰り返された場合、同じ行と行バージョンが返されますか?
特定の保証は、トランザクションの論理的な終了時刻を指します。 一般に、論理終了時刻は、トランザクションがデータベースにコミットされる時刻です。 メモリ最適化テーブルがトランザクションによってアクセスされる場合、論理的な終了時刻は技術的には検証フェーズの始まりです。 (詳細については、「Memory-Optimized テーブルのトランザクション」のトランザクションの有効期間 に関する説明を参照してください。
分離レベルに関係なく、トランザクション (T) には常に独自の更新が表示されます。
READ UNCOMMITTED(読み取り処理が未コミットのトランザクションからも許可される状態)
読み取られたデータは、コミットされておらず、一貫しておらず、安定していない可能性があります。 ただし、T によって行われた以前の書き込み操作が含まれます。
リードコミット
読み取られたデータはコミットされます。
スナップショット
スナップショット分離の下で T によって実行されるすべての読み取り操作は、同じ論理読み取り時間を持ちます。これはトランザクションの始まりです。 データの読み取りは、論理読み取り時間の時点でコミットされ、一貫性が保証されます。 元の読み取り時間の時点で読み取りを繰り返すと、同じ結果が返されます。
反復可能な読み取り
読み取られたデータは、トランザクションの論理的な終了時刻までコミットされ、安定することが保証されます。
シリアライズ可能
REPEATABLE READ のすべての保証と、T によって実行されるすべてのシリアル化可能な読み取り操作に関するファントム回避およびトランザクション整合性。ファントム回避は、スキャン操作が T によって書き込まれた追加の行のみを返すことができるが、他のトランザクションによって書き込まれた行は返すことができないことを意味します。
次のトランザクションについて考えてみましょう。
set transaction isolation level read committed
go
begin transaction
-- remove all rows from t3; the related read operation is performed under read committed
-- isolation, as this is the default for the transaction
delete from t3
-- copy the contents from t1 to t3; the read on t1 is performed under the serializable
-- isolation level
insert t3 select * from t1 (serializable)
-- compare t3 and t1; note: the result set may not be empty, as rows may have been added
-- by other transaction before this select, due to the read committed isolation level
select * from t3 except t1
-- compare t1 and t3; note: the result set is empty, as no rows have been added to t1
-- since its contents were copied to t1, due to the serializable isolation level
select * from t1 except t3
commit
このトランザクションは、読み取りによってコミットされた分離の下で t3 からすべての行を削除し、シリアル化可能な分離の下で t1 から t3 にすべての行をコピーしてから、t1 と t3 を比較します。 テーブルが空になった後、一部の行 (t1 に含まれていない) が t3 に追加されている可能性があります。 コピーがシリアル化可能であったので、t1 に行は追加されませんでした。
トランザクションの最後の t1 からの読み取りは構文的に読み取りコミットされますが、実質的にシリアル化可能です。これは、シリアル化可能な分離の下で同じ読み取りがトランザクションで前に実行されたためです。シリアル化可能性により、読み取りがトランザクションの後の時点で実行されると、同じ行が返されます。
コンテナー間トランザクションと分離レベル
コンテナー間トランザクションは、ディスク ベース側 (ディスク ベース テーブルに対する操作用) とメモリ最適化側 (メモリ最適化テーブルに対する操作用) の 2 つの側面を持つものとして見ることができます。 これら 2 つの側面は、分離レベルが異なる場合があります。 実際、各側の個々の読み取り操作には、分離レベルが異なる場合があります。
次のいずれかの条件が満たされた場合、特定のトランザクション T のディスク ベース側が特定の分離レベル X に達します。
X から始まります。つまり、セッションの既定値は X でした。これは、
SET TRANSACTION ISOLATION LEVEL
実行したか、SQL Server の既定値であるためです。トランザクション中、既定の分離レベルは、
SET TRANSACTION ISOLATION LEVEL
を使用して X に変更されます。ディスク ベースのテーブルに対する読み取り操作は、構文
WITH (X)
を使用して分離レベル X で実行されます。
T の実行中に、メモリ最適化テーブルまたはネイティブ コンパイル ストアド プロシージャに対する読み取り操作が分離レベル Y で実行される場合、T のメモリ最適化側は分離レベル Y に達します。
次のトランザクションを例として考えてみましょう。 ここで、t1 と t2 はディスク ベースのテーブルであり、t3 と t4 はメモリ最適化テーブルです。
トランザクションのディスク ベース側は、そのレベルで開始されるため、読み取りコミットされた分離レベルに達します。 ディスク ベース側も、最初の読み取り操作がその分離レベルで実行されるため、反復可能な読み取りに達します。 トランザクションの最後の削除は、読み取りコミットされた分離レベルで実行されるため、新しい分離レベルは導入されません。
トランザクションのメモリ最適化側は、2 つのレベルのいずれかに到達できます。条件 1 が true の場合はシリアル化可能に達し、false の場合は、メモリ最適化側はスナップショット分離のみに達します。
set transaction isolation level read committed
go
begin transaction
select * from t1 (repeatableread)
if condition1 begin
insert t3 select * from t4 (serializable)
end
else begin
insert t3 select * from t4 (snapshot)
end
delete from t1
commit
コンテナー間トランザクションでサポートされる分離レベル
コンテナー間トランザクションのメモリ最適化テーブルに対する操作で使用される分離レベルには制限があります。
メモリ最適化テーブルでは、分離レベル SNAPSHOT、REPEATABLE READ、SERIALIZABLE がサポートされます。 自動コミット トランザクションの場合、メモリ最適化テーブルは分離レベル READ COMMITTED をサポートします。
次のシナリオがサポートされています。
READ UNCOMMITTED、READ COMMITTED、および READ_COMMITTED_SNAPSHOT のクロスコンテナートランザクションは、SNAPSHOT、REPEATABLE READ、SERIALIZABLE の各アイソレーション レベルの下でメモリ最適化テーブルを利用できます。 READ COMMITTED 保証はトランザクションに対して保持されます。トランザクションによって読み取られたすべての行がデータベースにコミットされています。
REPEATABLE READ および SERIALIZABLE トランザクションは、SNAPSHOT 分離の下でメモリ最適化テーブルにアクセスできます。
読み取り専用のクロスコンテナー トランザクション
SQL Server のほとんどの読み取り専用トランザクションは、コミット時にロールバックされます。 データベースにコミットする変更がないため、システムはトランザクションで使用されるリソースを解放するだけです。 読み取り専用ディスク ベースのトランザクションの場合、トランザクションによって取得されたすべてのロックは、現時点で解放されます。 1 つのネイティブ コンパイル プロシージャ実行にまたがる読み取り専用メモリ最適化トランザクションの場合、検証は実行されません。
自動コミットモードでは、コンテナー間で行われる読み取り専用トランザクションは、トランザクションの最後に単純にロールバックされます。 検証は実行されません。
明示的または暗黙的なクロスコンテナートランザクションは、トランザクションが REPEATABLE READ または SERIALIZABLE 分離の下でメモリ最適化テーブルにアクセスした場合、コミット時に検証を実行します。 検証の詳細については、 Memory-Optimized テーブルのトランザクションでの競合検出、検証、コミット依存関係チェックに関するセクションを参照してください。
こちらもご覧ください
Memory-Optimized テーブルのトランザクションについて
Memory-Optimized テーブルでのトランザクション分離レベルのガイドライン
Memory-Optimized テーブルでのトランザクションの再試行ロジックのガイドライン