次の方法で共有


Memory-Optimized テーブル内のトランザクション

SNAPSHOT 分離またはREAD_COMMITTED_SNAPSHOTを使用することで、ディスクベースのテーブルにおける行のバージョン管理はオプティミスティックコンカレンシー制御の形態を提供します。 リーダーとライターは互いをブロックしません。 メモリ最適化テーブルでは、ライターはライターをブロックしません。 ディスク ベースのテーブルで行のバージョン管理を行うと、1 つのトランザクションで行がロックされ、行の更新を試みる同時実行トランザクションはブロックされます。 メモリ最適化テーブルでのロックはありません。 代わりに、2 つのトランザクションが同じ行を更新しようとすると、書き込み/書き込み競合 (エラー 41302) が発生します。

ディスク ベースのテーブルとは異なり、メモリ最適化テーブルでは、分離レベルが高い REPEATABLE READ と SERIALIZABLE によるオプティミスティック コンカレンシー制御が可能になります。 分離レベルを確保するためにロックは使用されません。 代わりに、トランザクション検証の最後に、反復可能な読み取りまたはシリアル化可能性の前提条件が保証されます。 前提条件に違反した場合、トランザクションは終了します。 詳細については、「 トランザクション分離レベル」を参照してください。

メモリ最適化テーブルの重要なトランザクション セマンティクスは次のとおりです。

  • マルチバージョニング

  • スナップショット ベースのトランザクションの分離

  • 楽天的

  • 競合の検出

これらのセマンティクスのそれぞれについては、次のセクションで説明します。

Memory-Optimized テーブルでの複数バージョン管理

メモリ最適化テーブル内の行のバージョンは異なる場合があります。 同時実行トランザクションは、同じ行の異なるバージョンにアクセスする可能性があります。

メモリ最適化テーブル データはバージョンベースです。 任意の行に対して、異なる時点で有効な異なる行バージョンが存在する可能性があります。 ディスク ベースのテーブルでは、READ_COMMITTED_SNAPSHOTまたはALLOW_SNAPSHOT_ISOLATIONが ON の場合、異なる行バージョンが維持されます。 メモリ最適化テーブルでは、READ_COMMITTED_SNAPSHOTとALLOW_SNAPSHOT_ISOLATIONが OFF の場合でも、異なる行バージョンが維持されます。 メモリ最適化テーブルの行バージョンは tempdb に保持されません。 代わりに、行のバージョンは、メモリに行を格納するメモリ最適化データ構造の一部として、インラインで保持されます。

Memory-Optimized テーブルのトランザクション分離の Snapshot-Based

1 つのトランザクション内のすべての操作では、メモリ最適化テーブルの同じトランザクション整合性スナップショットが使用されます。 メモリ最適化テーブルのすべてのトランザクション分離はスナップショット ベースです。 たとえば、シリアル化可能な分離レベルを使用してメモリ最適化テーブルにアクセスするトランザクションでは、同じトランザクション整合性スナップショットに対してすべての操作が実行されます。

メモリ最適化テーブルにアクセスするトランザクションでは、この行のバージョン管理を使用して、テーブル内の行のトランザクション整合性スナップショットを取得します。 トランザクション内のステートメントによって読み取られたデータは、トランザクションの開始時に存在していたデータのトランザクション整合性バージョンになります。 したがって、同時に実行されるトランザクションによって行われた変更は、現在のトランザクション内のステートメントには表示されません。

Memory-Optimized テーブルのオプティミスティック コンカレンシー制御

競合とエラーはまれであり、メモリ最適化テーブルのトランザクションでは、同時実行トランザクションと競合がないと想定し、操作が成功します。 トランザクションは、メモリ最適化テーブルにおいてトランザクション分離を保証するためのロックやラッチを使用しません。 著者は読者を遮ることはありません。 ライターはライターをブロックしません。 代わりに、トランザクションは、他のトランザクションとの競合が発生しないという (オプティミスティックな) 前提の下で続行されます。 ロックとラッチを使用せず、他のトランザクションが同じ行の処理を完了するのを待たないと、パフォーマンスが向上します。

さらに、トランザクション (TxA) が、コミット中の別のトランザクション (TxB) によって挿入または変更された行を読み取る場合、コミットが発生するのを待つのではなく、他のトランザクションがコミットされると楽観的に想定されます。 この場合、トランザクション TxA はトランザクション TxB にコミット依存関係を取ります。

競合の検出、検証、およびコミット依存性のチェック

SQL Server は、同時実行トランザクション間の競合と分離レベル違反を検出し、競合するトランザクションの 1 つを終了します。 このトランザクションは再試行する必要があります。 (詳細については、「 Memory-Optimized テーブルでのトランザクションの再試行ロジックのガイドライン」を参照してください)。

システムは、競合がなく、トランザクション分離の違反もないことを楽観的に想定しています。 データベースに不整合が発生したり、トランザクションの分離に違反したりする可能性がある競合が発生した場合、これらの競合が検出され、トランザクションが終了します。

競合が検出された場合、トランザクションは終了し、クライアントは再試行する必要があります。

次の表は、メモリ最適化テーブルにアクセスするトランザクションのエラー条件をまとめたものです。

メモリ最適化テーブルにアクセスするトランザクションのエラー条件。

エラー シナリオ
書き込みの競合。 トランザクションの開始後に更新されたレコードを更新しようとしています。 同時実行トランザクションによって更新または削除された行を更新または削除します。
REPEATABLE READ の検証の失敗。 トランザクションによって読み取られた行が、トランザクションの開始後に変更 (更新または削除) されました。 反復可能な読み取り検証は、通常、REPEATABLE READ および SERIALIZABLE トランザクション分離レベルを使用する場合に発生します。
SERIALIZABLE の検証の失敗。 トランザクションが開始されてから、トランザクション内のいずれかのスキャン範囲に新しい (ファントム) 行が挿入されました。 トランザクションが開始される前に行がデータベースにコミットされていた場合、その行はトランザクションに表示されます。 SERIALIZABLE 検証は、通常、SERIALIZABLE 分離を使用して PRIMARY KEY 制約を検証するときに発生します。
コミット依存関係の失敗。 トランザクションは、このテーブルのエラーの 1 つ、メモリ不足の状態、またはトランザクション ログへのコミットに失敗したために、コミットに失敗した別のトランザクションに依存しました。 このエラーは、読み取り/書き込みトランザクションと読み取り専用トランザクションの両方で発生する可能性があります。

トランザクションの有効期間

前の表で説明したエラーは、トランザクション中に異なるポイントで発生する可能性があります。 次の図は、メモリ最適化テーブルにアクセスするトランザクションのフェーズを示しています。

トランザクションの有効期間。 メモリ最適化テーブルにアクセスするトランザクションの有効期間。

通常の処理

このフェーズでは、ユーザーが発行した Transact-SQL ステートメントが実行されます。 テーブルから行が読み取られ、新しい行バージョンがデータベースに書き込まれます。 トランザクションは、他のすべての同時実行トランザクションから分離されます。 トランザクションでは、トランザクションの開始時に存在するメモリ最適化テーブルのスナップショットが使用されます。

トランザクションのこのフェーズのテーブルへの書き込みはまだ他のトランザクションには表示されません。ただし、行の更新と削除は、書き込みの競合を検出するために、他のトランザクションの更新操作と削除操作に表示されます。

更新操作または削除操作で、トランザクションの論理開始以降に行が更新または削除されたことが確認された場合、操作はエラー 41302 で失敗します。 エラー 41302 のメッセージは、「現在のトランザクションは、このトランザクションの開始後に更新されたテーブル X のレコードを更新しようとしました。 トランザクションが中止されました。

このエラーはトランザクションを終了します (XACT_ABORTが OFF の場合でも)。つまり、ユーザー セッションが終了するとトランザクションがロールバックされます。 Doomed トランザクションはコミットできず、ログに書き込まず、メモリ最適化テーブルにアクセスしない読み取り操作のみをサポートします。

依存関係のコミット

通常の処理中に、トランザクションは、検証フェーズまたはコミット フェーズにあるが、まだコミットしていない他のトランザクションによって書き込まれた行を読み取ることができます。 トランザクションの論理終了時刻が検証フェーズの開始時に割り当てられているため、行が表示されます。

トランザクションがそのようなコミットされていない行を読み取ると、そのトランザクションに対するコミット依存関係が取得されます。 これには、主に次の 2 つの影響があります。

  • トランザクションは、依存するトランザクションがコミットされるまでコミットできません。 つまり、すべての依存関係がクリアされるまで、コミット フェーズに入ることはできません。

  • さらに、すべての依存関係がクリアされるまで、結果セットはクライアントに返されません。 これにより、クライアントはコミットされていないデータを監視できなくなります。

依存トランザクションのいずれかがコミットに失敗した場合、コミット依存関係エラーが発生します。 つまり、トランザクションはエラー 41301 でコミットに失敗します ("現在のトランザクションが依存関係を取った以前のトランザクションは中止され、現在のトランザクションはコミットできなくなります。")。

検証フェーズ

検証フェーズ中、システムは、要求されたトランザクション分離レベルに必要な前提条件が、トランザクションの論理開始と論理終了の間に当てはまることを検証します。

検証フェーズの開始時に、トランザクションに論理終了時刻が割り当てられます。 データベースに書き込まれた行バージョンは、論理終了時刻に他のトランザクションに表示されます。 詳細については、「コミット依存関係」を参照してください。

反復可能な読み取り検証

トランザクションの分離レベルが REPEATABLE READ または SERIALIZABLE の場合、または REPEATABLE READ または SERIALIZABLE 分離の下でテーブルにアクセスされる場合 (詳細については、 トランザクション分離レベルでの個々の操作の分離に関するセクションを参照)、システムは読み取りが繰り返し可能であることを検証します。 つまり、トランザクションによって読み取られた行のバージョンが、トランザクションの論理終了時刻に有効な行バージョンであることを検証します。

いずれかの行が更新または変更された場合、トランザクションはエラー 41305 でコミットに失敗します ("現在のトランザクションは、反復可能な読み取り検証エラーのためコミットに失敗しました。")。

このエラーは、挿入、更新、または削除操作の後、およびトランザクションのコミット前にテーブルが削除された場合にも発生する可能性があります。 これは、ネイティブ コンパイル ストアド プロシージャの挿入、更新、または削除操作にのみ適用されます。 このような書き込み操作は、解釈された Transact-SQL によって実行され、DROP TABLE ステートメントがブロックされ、トランザクションがコミットされるまで待機します。

シリアル化可能な検証

シリアル化可能な検証は、次の 2 つの場合に実行されます。

  • トランザクションの分離レベルが SERIALIZABLE の場合、または SERIALIZABLE 分離の下でテーブルがアクセスされる場合。

  • PRIMARY KEY 制約に対して作成されたインデックスなど、一意のインデックスに行が挿入される場合。 システムは、同じキーを持つ行が同時に挿入されていないことを検証します。

システムは、ファントム行がデータベースに書き込まれなかったことを検証します。 トランザクションによって実行される読み取り操作が評価され、これらの読み取り操作のスキャン範囲に新しい行が挿入されなかったことが確認されます。

一意インデックスへのキーの挿入には、キーが重複していないかどうかを判断するための暗黙的な読み取り操作が含まれます。 一意のインデックスに対してシリアル化可能な検証により、2 つのトランザクションで同じキーが同時に挿入された場合に、これらのインデックスに重複を含めないようにします。

ファントム行が検出された場合、トランザクションはエラー 41325 でコミットに失敗します ("シリアル化可能な検証エラーが原因で現在のトランザクションがコミットに失敗しました")。

コミット処理

検証が成功し、すべてのトランザクション依存関係がクリアされると、トランザクションはコミット処理フェーズに入ります。 このフェーズでは、持続性を確保するために、永続テーブルへの変更がログに書き込まれ、ログがディスクに書き込まれます。 トランザクションのログ レコードがディスクに書き込まれると、制御がクライアントに返されます。

このトランザクションに対するすべてのコミット依存関係がクリアされ、このトランザクションのコミットを待機していたすべてのトランザクションを続行できます。

制限事項

  • 複数データベースにまたがるトランザクションは、メモリ最適化テーブルではサポートされていません。 メモリ最適化テーブルにアクセスするすべてのトランザクションは、tempdb への読み取り/書き込みアクセスとシステム データベース マスターへの読み取り専用アクセスを除き、複数のデータベースにアクセスできません。

  • 分散トランザクションは、メモリ最適化テーブルではサポートされていません。 BEGIN DISTRIBUTED TRANSACTION で開始された分散トランザクションは、メモリ最適化テーブルにアクセスできません。

  • メモリ最適化テーブルはロックをサポートしていません。 ロック ヒント (TABLOCK、XLOCK、ROWLOCK など) による明示的なロックは、メモリ最適化テーブルではサポートされていません。

こちらもご覧ください

Memory-Optimized テーブルのトランザクションについて