適用対象:SQL Server
Azure SQL データベース
Azure SQL Managed Instance
メモリ最適化テーブルは、CREATE TABLE (Transact-SQL) を使用して作成されます。
メモリ最適化テーブルは既定では完全に持続性があり、従来のディスクベース テーブルのトランザクションと同様に、メモリ最適化テーブルのトランザクションは完全に原子性、一貫性、分離性、持続性 (ACID) を備えています。 メモリ最適化テーブルおよびネイティブ コンパイル ストアド プロシージャは、Transact-SQL 機能のサブセットのみをサポートします。
SQL Server 2016 以降、および Azure SQL Database では、インメモリ OLTP に固有の 照合順序またはコード ページ に関する制限はありません。
メモリ最適化テーブルのプライマリ ストレージは、メイン メモリです。 テーブルの行は、メモリから読み込まれ、メモリに書き込まれます。 ディスク上にはテーブル データの 2 番目のコピーが保持されますが、持続性を実現するためのものにすぎません。 持続性のあるテーブルの詳細については、「 メモリ最適化オブジェクト用ストレージの作成と管理 」を参照してください。 メモリ最適化テーブル内のデータは、データベースの復旧中 (サーバーの再起動後など) にのみディスクから読み取られます。
パフォーマンスをさらに向上するために、インメモリ OLTP ではトランザクションの持続性が遅延している状態の持続性テーブルがサポートされます。 遅延された耐久性のあるトランザクションは、トランザクションがコミットされ、制御がクライアントに戻った直後にディスクに保存されます。 パフォーマンスの向上と引き換えに、ディスクに保持されないコミット済みトランザクションは、サーバーのクラッシュまたはフェールオーバーで失われます。
既定の永続メモリ最適化テーブルに加えて、SQL Server では非永続メモリ最適化テーブルもサポートされています。このテーブルはログに記録されず、そのデータはディスクに保持されません。 つまり、これらのテーブルのトランザクションではディスク IO は必要ありませんが、サーバーのクラッシュまたはフェールオーバーが発生した場合、データは失われます。
インメモリ OLTP は、開発、配置、管理、サポートなど、すべての領域においてシームレスな使用環境を提供するために、SQL Server と統合されています。 データベースには、ディスク ベースのオブジェクトと同様にインメモリのオブジェクトを含めることができます。
メモリ最適化テーブル内の行には、バージョンが付いています。 これは、テーブルの各行に複数のバージョンが存在する可能性があることを意味します。 行バージョンはいずれも、同じテーブル データ構造で保持されます。 行のバージョン管理は、同じ行に対して読み取りと書き込みを同時に実行できるようにするために使用します。 同じ行に対して読み取りおよび書き込みを同時に実行する方法の詳細については、「 Transactions with Memory-Optimized Tables (メモリ最適化テーブルでのトランザクション)」を参照してください。
次の図は、複数バージョン管理について説明したものです。 この図では、行が 3 つあるテーブルを示しています。行のそれぞれに、バージョンが複数存在します。
テーブルには、r1、r2、および r3 の 3 行があります。 r1 には 3 つ、r2 には 2 つ、r3 には 4 つのバージョンがあります。 同じ行のバージョンが異なると、必ずしも連続するメモリの場所が占有されるとは限りません。 バージョンの異なる行がテーブル データ構造のさまざまな場所に分散して配置されていることもあります。
メモリ最適化テーブルのデータ構造は、行バージョンのコレクションと考えることができます。 ディスク ベース テーブルの行がページとエクステントによって整理され、個々の行がページ番号とページ オフセットでアドレス指定されているのに対して、メモリ最適化テーブルの行バージョンは、8 バイトのメモリ ポインターを使用してアドレスが指定されています。
メモリ最適化テーブルのデータには、次の 2 つの方法でアクセスできます。
ネイティブ コンパイル ストアド プロシージャを経由してアクセスできます。
ネイティブ コンパイル ストアド プロシージャの外部で、解釈された Transact-SQL を使用します。 これらの Transact-SQL ステートメントは、解釈されたストアド プロシージャ内にあっても、アドホック Transact-SQL ステートメントであってもかまいません。
メモリ最適化テーブルのデータへのアクセス
メモリ最適化テーブルには、ネイティブ コンパイル ストアド プロシージャ (「ネイティブ コンパイル ストアド プロシージャ」) からアクセスするのが最も効率的です。 メモリ最適化テーブルのデータには、(従来の) 解釈された Transact-SQL でもアクセスできます。 解釈された Transact-SQL とは、ネイティブ コンパイル ストアド プロシージャを使用せずにメモリ最適化テーブルにアクセスすることを表します。 解釈された Transact-SQL アクセスの例として、DML トリガー、アドホック Transact-SQL バッチ、ビュー、およびテーブル値関数からのメモリ最適化テーブルへのアクセスがあります。
次の表に、さまざまなオブジェクトへのネイティブ アクセスおよび解釈された Transact-SQL アクセスを示します。
機能 | ネイティブ コンパイル ストアド プロシージャを使用したアクセス | 解釈された Transact-SQL アクセス | CLR アクセス |
---|---|---|---|
メモリ最適化テーブル | はい | はい | いいえ1 |
メモリ最適化テーブル型 | はい | はい | いいえ |
ネイティブ コンパイル ストアド プロシージャ | ネイティブ コンパイル ストアド プロシージャの入れ子がサポートされるようになりました。 参照先のプロシージャがネイティブにコンパイルされている場合は、ストアド プロシージャ内で EXECUTE 構文を使用できます。 | はい | いいえ* |
1コンテキスト接続 (CLR モジュールの実行時に SQL Server からの接続) からメモリ最適化テーブルまたはネイティブ コンパイル ストアド プロシージャにアクセスすることはできません。 ただし、別の接続を作成して開き、そこからメモリ最適化テーブルおよびネイティブ コンパイル ストアド プロシージャにアクセスできます。
メモリ最適化テーブル内の機密データは、 Always Encrypted を使用して保護できます。 次の制限事項が適用されます。
- セキュリティで保護されたエンクレーブで Always Encrypted を使用する場合、メモリ最適化テーブルの列にエンクレーブ対応キーを使用することはできません。 これは、インプレース暗号化を使用できないことを意味し、初期暗号化はクライアントで行われます。
- テーブルがネイティブ コンパイル モジュールで参照されている場合、Always Encrypted はメモリ最適化テーブルの列ではサポートされません。
パフォーマンスとスケーラビリティ
次の要因は、In-Memory OLTP で実現できるパフォーマンスの向上に影響します。
通信: 多数の短いストアド プロシージャ呼び出しを使用するアプリケーションでは、呼び出しが少なく、各ストアド プロシージャに実装される機能が多いアプリケーションと比較して、パフォーマンスの向上が小さい場合があります。
Transact-SQL 実行: インメモリ OLTP は、解釈されたストアド プロシージャやクエリ実行ではなく、ネイティブ コンパイル ストアド プロシージャを使用する場合に、最高のパフォーマンスを発揮します。 こうしたストアド プロシージャからメモリ最適化テーブルにアクセスすると有利な場合があります。
範囲スキャンとポイント参照: メモリ最適化された非クラスター化インデックスでは、範囲スキャンと並べ替えられたスキャンがサポートされています。 ポイント参照については、メモリ最適化された非クラスター化インデックスよりもメモリ最適化されたハッシュ インデックスの方がパフォーマンスが優れています。 メモリ最適化された非クラスター化インデックスはディスク ベース インデックスよりもパフォーマンスが優れています。
- SQL Server 2016 以降、メモリ最適化テーブルのクエリ プランでは並列でテーブルをスキャンできます。 これにより、分析クエリのパフォーマンスが向上します。
- ハッシュ インデックスも、SQL Server 2016 で並列スキャン可能になりました。
- 非クラスター化インデックスも、SQL Server 2016 で並列スキャン可能になりました。
インデックス操作: インデックス操作はログに記録されず、メモリ内にのみ存在します。
コンカレンシー: ラッチの競合やブロックなど、エンジンレベルのコンカレンシーがパフォーマンスに影響するアプリケーションの場合、アプリケーションをインメモリ OLTP に移行するとパフォーマンスが大幅に向上します。
次の表は、リレーショナル データベースで一般的に生じるパフォーマンスとスケーラビリティの問題、およびインメモリ OLTP によってどのようにパフォーマンスが向上するかを示しています。
問題点 | インメモリ OLTP の影響 |
---|---|
パフォーマンス リソース (CPU、I/O、ネットワーク、またはメモリ) の使用率が高い。 |
CPU (中央処理装置) ネイティブ コンパイル ストアド プロシージャは、解釈されるストアド プロシージャと比較して、Transact-SQL ステートメントの実行に必要な命令が少なくなるため、CPU 使用率が大幅に低下する可能性があります。 In-Memory OLTP は、1 つのサーバーが複数のサーバーのスループットを提供する可能性があるため、スケールアウトされたワークロードへのハードウェア投資を削減するのに役立ちます。 入力/出力 データやインデックス ページに対する処理に起因する I/O のボトルネックが発生する場合、インメモリ OLTP ではボトルネックを低減できます。 さらに、In-Memory OLTP オブジェクトのチェックポイント処理は継続的であり、I/O 操作が急激に増加することはありません。 ただし、パフォーマンス クリティカル なテーブルのワーキング セットがメモリに収まらない場合、データがメモリ常駐である必要があるため、In-Memory OLTP は適用されません。 ログ記録で I/O のボトルネックが発生する場合、インメモリ OLTP はログ記録が少ないためボトルネックを軽減できます。 1 つ以上のメモリ最適化テーブルが持続性のないテーブルとして構成されている場合は、データのログ記録を無効にできます。 [メモリ] In-Memory OLTP にはパフォーマンス上の利点はありません。 インメモリ OLTP では、オブジェクトがメモリ常駐型であることが必要になるため、メモリの負荷が増加する可能性があります。 ネットワーク In-Memory OLTP にはパフォーマンス上の利点はありません。 データは、データ層からアプリケーション層に渡す必要があります。 |
スケーラビリティ SQL Server アプリケーションでのスケーリングの問題のほとんどは、ロック、ラッチ、スピンロックの競合など、同時実行の問題が原因です。 |
ラッチの競合 一般的なシナリオとして、キー順に行を同時に挿入した場合の、インデックスの最終ページでの競合を挙げることができます。 In-Memory OLTP はデータにアクセスするときにラッチを受け取らないため、ラッチの競合に関連するスケーラビリティの問題は完全に削除されます。 スピンロックの競合 In-Memory OLTP はデータにアクセスするときにラッチを受け取らないため、スピンロックの競合に関連するスケーラビリティの問題は完全に削除されます。 ロックに関連する競合 データベース アプリケーションで読み取り操作と書き込み操作の間にブロックの問題が発生した場合、インメモリ OLTP では、新しい形式のオプティミスティック コンカレンシーを使用してすべてのトランザクション分離レベルを実装するため、ブロックの問題は排除されます。 In-Memory OLTP では、行バージョンを格納するために TempDB は使用されません。 2 つの同時実行トランザクションで同じ行を更新しようとした場合など、2 つの書き込み操作間の競合によってスケーリングの問題が発生した場合、インメモリ OLTP では、一方のトランザクションが成功し、他方のトランザクションは失敗するようになります。 失敗したトランザクションは、明示的または暗黙的に再送信し、トランザクションを再試行する必要があります。 いずれの場合も、アプリケーションに変更を加える必要があります。 アプリケーションで 2 つの書き込み操作間の競合が頻繁に発生する場合、オプティミスティック ロックの価値は減少します。 このアプリケーションは、In-Memory OLTP には適していません。 ほとんどの OLTP アプリケーションでは、ロックエスカレーションの結果である場合を除き、書き込みの競合はありません。 |
メモリ最適化テーブルの行レベルのセキュリティ
行レベルのセキュリティ はメモリ最適化テーブルでサポートされます。 行レベルのセキュリティ ポリシーは、基本的には、ディスク ベース テーブルと同じように、メモリ最適化テーブルに適用できますが、セキュリティ述語として使用されるインライン テーブル値関数をネイティブにコンパイル (WITH NATIVE_COMPILATION オプションを使用して作成) しなければならない場合を除きます。 詳細については、「 行レベルのセキュリティ 」トピックの「 Cross-Feature Compatibility (機能間の互換性) 」セクションを参照してください。
メモリ最適化テーブルでは、行レベルのセキュリティに不可欠なさまざまな組み込みセキュリティ関数を使用できます。 詳細については、「 ネイティブ コンパイル モジュールの組み込み関数」を参照してください。
EXECUTE AS CALLER - ヒントが指定されていない場合でも、すべてのネイティブ モジュールで EXECUTE AS CALLER が既定でサポートされ、使用されるようになりました。 これは、すべての行レベルのセキュリティ述語関数で EXECUTE AS CALLER が使用され、関数とその中で使用される組み込み関数が呼び出し元ユーザーのコンテキストで評価されることが想定されるためです。
EXECUTE AS CALLER には、呼び出し元のアクセス許可チェックによるパフォーマンス ヒットがそれほどありません (約 10%)。 モジュールで EXECUTE AS OWNER または EXECUTE AS SELF が明示的に指定されている場合、これらのアクセス許可チェックとそれに関連するパフォーマンス コストは回避されます。 ただし、これらのオプションのいずれかを前述の組み込み関数と共に使用すると、必要なコンテキスト切り替えにより、パフォーマンスが向上します。
シナリオ
インメモリ OLTP によってパフォーマンスを向上できる典型的なシナリオの概要については、「インメモリ OLTP」を参照してください。