インメモリ OLTP により、メモリ最適化テーブルには完全な持続性が提供されます。 メモリ最適化テーブルを変更したトランザクションがコミットされると、基になるストレージが使用可能な場合、SQL Server では、(ディスク ベース テーブルの場合と同様に) この変更が永続的である (データベースの再起動後も保持される) ことが保証されます。 持続性には、トランザクション ログとディスク上ストレージでのデータ変更の保持という、2 つの主なコンポーネントがあります。
トランザクション ログ
ディスク ベース テーブルまたは持続性のあるメモリ最適化テーブルに対するすべての変更は、1 つ以上のトランザクション ログ レコードにキャプチャされます。 トランザクションのコミット時に、SQL Server は、トランザクションに関連付けられているログ レコードをディスクに書き込んだ後、トランザクションによってコミットされたアプリケーションまたはユーザー セッションと通信します。 これにより、トランザクションによる変更が持続可能であることが保証されます。 メモリ最適化テーブルのトランザクション ログは、ディスク ベース テーブルで使用されている同じログ ストリームと完全に統合されています。 この統合によって、既存のトランザクション ログ バックアップ、復旧、および復元操作は引き続き機能し、追加の手順は必要ありません。 ただし、In-Memory OLTP はワークロードのトランザクション スループットを大幅に向上させる可能性があるため、増加する IO 要件を処理するためにトランザクション ログ ストレージが適切に構成されていることを確認する必要があります。
データ ファイルとデルタ ファイル
メモリ最適化テーブル内のデータは、1 つ以上のメモリ内インデックスを介してリンクされた自由形式のデータ行としてメモリに格納されます。 ディスク ベース テーブルで使用されるような、データ行のページ構造はありません。 アプリケーションがトランザクションをコミットする準備ができたら、In-Memory OLTP によってトランザクションのログ レコードが生成されます。 メモリ最適化テーブルの永続化は、バックグラウンド スレッドを使用して一連のデータ ファイルとデルタ ファイルを使用して行われます。 データ ファイルとデルタ ファイルは 1 つ以上のコンテナーにあります (FILESTREAM データで使用される同様のメカニズムを使用しています)。 これらのコンテナーは、メモリ最適化ファイル グループと呼ばれる新しい種類のファイル グループにマップされます。
データはこれらのファイルに厳密な順次形式で書き込まれるため、スピン メディアの場合のディスク待機時間が最小限に抑えられます。 異なるディスクにある複数のコンテナーを使用して、I/O 動作を分散することもできます。 異なるディスク上の複数のコンテナー内のデータ ファイルとデルタ ファイルは、ディスク上のデータファイルと差分ファイルからメモリにデータを読み取るときに回復パフォーマンスを向上させます。
アプリケーションは、データ ファイルとデルタ ファイルに直接アクセスしません。 すべてのデータの読み取りと書き込みでは、メモリ内データが使用されます。
データ ファイル
データ ファイルには、1 つ以上のメモリ最適化テーブルからの行が格納されます。これらの行は、INSERT 操作や UPDATE 操作の一部である複数のトランザクションによって挿入されたものです。 たとえば、ある行はメモリ最適化テーブル T1 から挿入され、次の行はメモリ最適化テーブル T2 から挿入されることがあります。 これらの行は、データ アクセスが順次的になるように、トランザクション ログ内のトランザクションの順序でデータ ファイルに追加されます。 これにより、ランダム I/O と比較した場合、I/O スループットが大幅に向上します。 各データ ファイルのサイズは、メモリが 16 GB を超えるコンピューターでは約 128 MB、16 GB 以下のコンピューターでは 16 MB にサイズ設定されます。 データ ファイルがいっぱいになると、新しいトランザクションによって挿入される行は別のデータ ファイルに格納されます。 時間の経過と同時に、持続性のあるメモリ最適化テーブルの行は、複数のデータ ファイルの 1 つと、非結合の連続したトランザクション範囲の行を含む各データ ファイルに格納されます。 たとえば、トランザクションのコミット タイムスタンプの範囲が (100, 200) であるデータ ファイルには、コミット タイムスタンプが 100 より大きく 200 以下のトランザクションによって挿入されたすべての行が含まれています。 コミット タイムスタンプとは、コミットの準備ができたトランザクションに割り当てられる、単調に増加する数値です。 各トランザクションには、一意のコミット タイムスタンプが設定されます。
行が削除または変更されるときは、その行がデータ ファイル内で実際に削除または変更されるのではなく、デルタ ファイルという別の種類のファイルによって、削除された行の追跡が行われます。 更新操作は、それぞれの行の削除操作と挿入操作の組み合わせとして処理されます。 これにより、データ ファイルでランダム IO が発生しないようになっています。
デルタ ファイル
各データ ファイルには、同じトランザクション範囲を持つデルタ ファイルが対応付けられています。デルタ ファイルは、そのトランザクション範囲のトランザクションによって挿入された削除済みの行を追跡します。 このデータ ファイルとデルタ ファイルはチェックポイント ファイル ペア (CFP) と呼ばれます。これは Merge 操作の単位であるとともに、割り当てと割り当て解除の単位でもあります。 たとえば、トランザクション範囲 (100、200) に対応するデルタ ファイルには、範囲 (100、200) のトランザクションによって挿入された削除済みの行が格納されます。 データ ファイルと同様に、デルタ ファイルは順次アクセスされます。
行の削除時には、データ ファイルから行が削除されるのではなく、その行への参照が、このデータ行が挿入されたトランザクション範囲に関連付けられているデルタ ファイルに追加されます。 削除対象のデータ行は既にデータ ファイルに存在するため、デルタ ファイルには参照情報 ( {inserting_tx_id, row_id, deleting_tx_id } ) が格納されるだけです。格納順序は、元の削除操作または更新操作のトランザクション ログの順序に従います。
データ ファイルとデルタ ファイルの取り込み
データ ファイルとデルタ ファイルは、オフライン チェックポイントと呼ばれるバックグラウンド スレッドによって設定されます。 このスレッドは、メモリ最適化テーブルでコミットされたトランザクションによって生成されたトランザクション ログ レコードを読み取り、挿入および削除された行に関する情報を適切なデータ ファイルとデルタ ファイルに追加します。 ディスク ベース テーブルでは、チェックポイントの完了時にデータやインデックス ページがランダム I/O でフラッシュされますが、これとは異なり、メモリ最適化テーブルの永続化は連続的なバックグラウンド操作によって行われます。 トランザクションでは、それ以前のいずれかのトランザクションによって挿入された任意の行が削除または更新されることがあるため、複数のデルタ ファイルへのアクセスが発生します。 削除情報は常にデルタ ファイルの末尾に追加されます。 たとえば、下に示す図では、コミット タイムスタンプが 600 のトランザクションでは、1 つの新しい行が挿入され、コミット タイムスタンプが 150、250、および 450 のトランザクションによって挿入された行が削除されます。 4 つのファイル I/O 操作 (3 つは削除された行が対象で、1 つは新しく挿入された行が対象) はすべて、対応するデルタ ファイルとデータ ファイルに対する追加専用の操作です。
データ ファイルとデルタ ファイルへのアクセス
データ ファイルとデルタ ファイルのペアにアクセスするのは次のような場合です。
オフライン チェックポイント スレッド このスレッドは、メモリ最適化データ行に対する挿入と削除を、対応するデータとデルタ ファイルのペアに追加します。
マージ操作 操作は、1 つ以上のデータ とデルタ ファイルのペアをマージし、新しいデータ とデルタ ファイルのペアを作成します。
クラッシュ復旧中に SQL Server を再起動するか、データベースをオンラインに戻すと、データとデルタ ファイルのペアを使用してメモリ最適化データが設定されます。 デルタ ファイルは、対応するデータ ファイルから行を読み取るときに、削除された行のフィルターとして機能します。 データ ファイルとデルタ ファイルのペアは独立しているため、データをメモリに取り込む時間を削減するために、これらのファイルは並列処理で読み込まれます。 データがメモリに読み込まれると、インメモリ OLTP エンジンは、メモリ最適化データが完全になるように、まだチェックポイント ファイルで扱われていないアクティブなトランザクション ログ レコードを適用します。
復元操作中に、In-Memory OLTP チェックポイント ファイルがデータベース バックアップから作成され、1 つ以上のトランザクション ログ バックアップが適用されます。 クラッシュ後の復旧の場合と同様に、インメモリ OLTP エンジンはデータを並列処理でメモリに読み込むので、復旧時間への影響を最小限に抑えることができます。
データ ファイルとデルタ ファイルのマージ
メモリ最適化テーブルのデータは、1 つ以上のデータ ファイルとデルタ ファイルのペア (チェックポイント ファイル ペアまたは CFP とも呼ばれます) に格納されます。 データ ファイルは挿入された行を格納し、デルタ ファイルは削除された行を参照します。 OLTP ワークロードの実行中、DML 操作によって行が更新、挿入、および削除されると、新しい行を保存するために新しい CFP が作成され、削除された行への参照がデルタ ファイルに追加されます。
以前に閉じられ、現在アクティブなすべての CFP のメタデータは、ストレージ アレイと呼ばれる内部配列構造に格納されます。 これは、CFP の有限サイズ (8,192 エントリ) 配列です。 ストレージ アレイ内のエントリは、トランザクション範囲で並べ替えられます。 ストレージ アレイ内の CFP (ログの末尾と共に) は、メモリ最適化テーブルを使用してデータベースを復旧するために必要なすべてのディスク上の状態を表します。
DML 操作では時間の経過と共に、CFP の数が増え、ストレージ アレイが容量に達する原因となり、次の課題が発生します。
削除された行。 削除された行はデータ ファイルに残りますが、対応するデルタ ファイルでは削除済みとしてマークされます。 これらの行は不要になり、ストレージから削除されます。 削除された行が CFP から削除されなかった場合、領域が不必要に使用され、復旧時間が遅くなります。
ストレージ アレイがいっぱいです。 ストレージ アレイに 8,000 個のエントリが割り当てられている場合 (配列内の 192 個のエントリは、競合する既存のマージ用に予約されているか、手動でマージできるように予約されています)、永続メモリ最適化テーブルで新しい DML トランザクションを実行することはできません。 残りのエントリを使用できるのは、チェックポイント操作とマージ操作だけです。 これにより、DML トランザクションが配列を埋めず、配列内の一部のエントリが既存のファイルをマージし、配列内の領域を再利用するために予約されることが保証されます。
ストレージアレイ操作のオーバーヘッド。 内部プロセスは、削除された行に関する情報を追加するデルタ ファイルの検索などの操作をストレージ アレイで検索します。 これらの操作のコストは、エントリの数と共に増加します。
このような非効率性を防ぐために、以下で説明するマージ ポリシーに基づいて古い閉じた CFP がマージされるため、ストレージ アレイは同じデータ セットを表すように圧縮され、CFP の数が少なくなります。
データベース内のすべての永続テーブルのメモリ内合計サイズは、250 GB を超えないようにしてください。 最大 250 GB のメモリを使用する非消耗品テーブルでは、挿入、削除、更新の操作を想定して、平均 500 GB のストレージ領域が必要になります。 500 GB のストレージ領域をサポートするには、メモリ最適化ファイル グループ内の 4,000 個のデータ とデルタ ファイルのペアが必要です。
データベース アクティビティの短期的な急増により、チェックポイント操作とマージ操作のラグが発生し、必要なデータとデルタ ファイルのペアの数が増える可能性があります。 データベース アクティビティの短期的な急増に対応するために、ストレージ システムは最大 8,000 個のデータとデルタ ファイルのペアを最大 1 TB のストレージに割り当てることができます。 この制限に達すると、チェックポイント操作が追いつくまで、データベースで新しいトランザクションは許可されません。 メモリ内の永続テーブルのサイズが長期間にわたって 250 GB を超える場合、ファイル ペアの上限が 8,000 に達する可能性があります。
マージ操作は、内部定義のマージ ポリシーに基づいて 1 つ以上の隣接する閉じた CFP (マージ ソースと呼ばれます) を入力として受け取り、マージ ターゲットと呼ばれる 1 つの結果 CFP を生成します。 ソース CFP の各デルタ ファイル内のエントリは、対応するデータ ファイルから行をフィルター選択して、不要なデータ行を削除するために使用されます。 ソース CFP の残りの行は、1 つのターゲット CPF に統合されます。 マージが完了すると、結果の CFP でソース CFP (マージ ソース) が置き換えられます。 マージ ソースの CFP は、移行フェーズを経た後でストレージから削除されます。
次の例では、メモリ最適化テーブルのファイル グループに、タイムスタンプが 500 の時点でデータ ファイルとデルタ ファイルのペアが 4 組あり、以前のトランザクションからのデータが含まれています。 たとえば、最初のデータ ファイルの行は、100 より大きく 200 以下のタイムスタンプを持つトランザクションに対応します。この範囲は (100, 200] と表すこともできます。 2 番目と 3 番目のデータ ファイルは、削除済みとしてマークされている行を考慮すると、入力率が 50% 未満になっています。 これらの 2 つの CFP をマージ操作で結合し、タイムスタンプが 200 より大きく 400 以下 (2 つのファイルの結合範囲) のトランザクションを含む新しい CFP を作成します。 すると、範囲が (500, 600] のもう 1 つの CFP と、トランザクション範囲が (200, 400] の空でないデルタ ファイルが現れます。これは、マージ操作と同時に、ソース CFP から他の行を削除するといったトランザクション アクティビティを実行できることを示しています。
バックグラウンド スレッドでは、閉じているすべての CFP がマージ ポリシーを使用して評価され、該当する CFP に対して 1 つ以上のマージ要求が開始されます。 これらのマージ要求は、オフライン チェックポイント スレッドによって処理されます。 マージ ポリシーの評価は定期的に実行され、チェックポイントが閉じられるときにも行われます。
SQL Server 2014 (12.x) マージ ポリシー
SQL Server 2014 (12.x) では、次のマージ ポリシーが実装されています。
削除された行を考慮した後、2 つ以上の連続する CFP を統合できる場合は、マージがスケジュールされます。これにより、結果の行は理想的なサイズの 1 CFP に収まります。 CFP の理想的なサイズは次のように決定されます。
コンピューターのメモリが 16 GB 以下の場合、データ ファイルは 16 MB、デルタ ファイルは 1 MB です。
コンピューターのメモリが 16 GB を超える場合、データ ファイルは 128 MB、デルタ ファイルは 16 MB です。
データ ファイルが 256 MB を超え、行の半分以上が削除された場合、1 つの CFP を自己マージできます。 1 つのトランザクションや複数の同時実行トランザクションが大量のデータを挿入または更新する場合など、データ ファイルのサイズが 128 MB を超える場合は、トランザクションが複数の CFP にまたがることはできません。
次に、マージ ポリシーに従った CFP のマージの例をいくつか示します。
| 隣接する CFP ソース ファイル (入力 %) | マージ対象 |
|---|---|
| CFP0 (30%)、CFP1 (50%)、CFP2 (50%)、CFP3 (90%) | (CFP0、CFP1) CFP2 は選択されません。これを含めると、結果のデータ ファイルが適切なサイズの 100% を超えることになります。 |
| CFP0 (30%)、CFP1 (20%)、CFP2 (50%)、CFP3 (10%) | (CFP0、CFP1、CFP2)。 ファイルは左から選択されます。 CTP3 は選択されません。これを含めると、結果のデータ ファイルが適切なサイズの 100% を超えることになります。 |
| CFP0 (80%)、CFP1 (30%)、CFP2 (10%)、CFP3 (40%) | (CFP1、CFP2、CFP3)。 ファイルは左から選択されます。 CFP0 はスキップされます。これを CFP1 と結合すると、結果のデータ ファイルが適切なサイズの 100% を超えることになるためです。 |
空き領域のある CFP がすべてマージに適合するとは限りません。 たとえば、2 つの隣接する CFP の入力率が 60% の場合、これらはマージの対象にならないため、各 CFP の 40% のストレージは未使用になります。 最悪のケースは、すべての CFP の入力率が 50% になり、ストレージが 50% しか使用されない場合です。 CFP がマージ対象にならず、削除済みの行がストレージに存在していても、それらの削除済みの行は、インメモリ ガベージ コレクションによって既にメモリからは削除されている場合があります。 ストレージとメモリの管理は、ガベージ コレクションから独立しています。 アクティブな CFP (すべての CFP が更新されるわけではありません) から取得されたストレージは、最大でメモリ内の持続性のあるテーブルのサイズの 2 倍になる可能性があります。
必要に応じて、sys.sp_xtp_merge_checkpoint_files (Transact-SQL) を呼び出すことによって、手動マージを明示的に実行できます。
CFP のライフ サイクル
CPF は、割り当てを解除する前に複数の状態に遷移します。 CFP は、いつでも、事前作成済み、建設中、アクティブ、マージ ターゲット、マージソース、バックアップ/HA に必要、TOMBSTONE への移行中、TOMBSTONE のいずれかのフェーズにあります。 これらのフェーズの説明については、「sys.dm_db_xtp_checkpoint_files (Transact-SQL)」を参照してください。
さまざまな状態の CFP によって取得されたストレージを考慮した後、持続性のあるメモリ最適化テーブルによって取得されるストレージ全体は、メモリ内のテーブルのサイズの 2 倍をはるかに超える可能性があります。 DMV sys.dm_db_xtp_checkpoint_files (Transact-SQL) を照会して、メモリ最適化ファイル グループ内のすべての CFP (フェーズを含む) を一覧表示できます。 データベースがフルリカバリモデルまたはバルクログリカバリモデル用に構成されている場合、CFP を MERGE SOURCE 状態から TOMBSTONE に移行し、最終的にガベージコレクションに至るまでに最大5回のチェックポイントが必要とされます。各チェックポイントの後には、トランザクションログのバックアップが続行されます。
チェックポイントの後にログ バックアップを手動で強制してガベージ コレクションを高速化できますが、これにより空の CFP が 5 つ追加されます (各サイズが 128 MB のデータ ファイルと 5 つのデータ/デルタ ファイルのペア)。 実稼動環境のシナリオでは、バックアップ方法の一環として実行される自動チェックポイントとログ バックアップにより、CFP はこれらのフェーズをシームレスに移行し、手動による操作は必要ありません。 ガベージ コレクション プロセスが実行されると、その影響として、メモリ最適化テーブルのあるデータベースのストレージ サイズがメモリ内のサイズに比べて大きくなる可能性があります。 CFP がメモリ内の永続メモリ最適化テーブルの最大サイズの 4 倍になることは珍しくありません。