メモリ管理アーキテクチャ ガイド
適用対象: SQL Server Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Analytics Platform System (PDW)
Windows 仮想メモリ マネージャー
Windows 仮想メモリ マネージャー (VMM) は、使用可能な物理メモリにコミット済みのアドレス空間をマップします。
さまざまなオペレーティング システムでサポートされている物理メモリ量の詳細については、Windows のマニュアルの「Windows のリリース別のメモリ制限」を参照してください。
仮想メモリ システムでは、仮想メモリと物理メモリの比率が 1:1 を超えるような物理メモリの設定を許可しています。 その結果、さまざまな物理メモリ構成のコンピューターで大規模なプログラムを実行できます。 しかし、すべてのプロセスの平均ワーキング セットを合わせた容量よりもはるかに大きな仮想メモリを使用すると、パフォーマンスが低下する可能性があります。
SQL Server メモリ アーキテクチャ
SQL Server では、メモリの確保と解放が必要に応じて動的に行われます。 通常、管理者は、SQL Serverに割り当てる必要があるメモリの量を指定する必要はありませんが、一部の環境ではオプションがまだ存在し、必要です。
ディスクの読み書きはコンピューター操作の中でも特にリソースを消費するので、どのようなデータベース ソフトウェアでも、ディスク I/O を最小限に抑えることを主な設計目標としています。 SQL Server では、データベースから読み取ったページを保持するバッファー プールがメモリ内に構築されます。 SQL Server のコードの大部分は、ディスクとバッファー プールの間の物理的な読み書きの回数が最も少なくなるように記述されています。 SQL Server では、次の 2 つの目標のバランスを取ることを目指しています。
- システム全体のメモリ不足を防ぐため、バッファー プールが大きくなりすぎないようにする。
- バッファー プールのサイズを最大にして、データベース ファイルの物理 I/O を最小限に抑える。
負荷の高いシステムでは、大量のメモリを実行する必要がある大規模なクエリでは、要求されたメモリの最小量を取得できず、メモリ リソースの待機中にタイムアウト エラーが発生します。 これを解決するには、 query wait オプションの値を増やします。 並列クエリの場合は、 max degree of parallelism オプションの値を減らすことを検討してください。
メモリ不足の負荷の高いシステムでは、クエリプランでマージ結合、並べ替え、ビットマップを使用するクエリは、クエリがビットマップに必要な最小メモリを取得しない場合にビットマップを削除できます。 これはクエリのパフォーマンスに影響を与える可能性があり、並べ替えプロセスがメモリに収まらない場合は、データベース内 tempdb
の作業テーブルの使用量が増加し、増加する tempdb
可能性があります。 この問題を解決するには、物理メモリを追加するか、別の高速クエリ プランを使用するようにクエリを調整します。
従来の (仮想) メモリ
すべてのSQL Serverエディションでは、64 ビット プラットフォームで従来のメモリがサポートされています。 SQL Server プロセスは、x64 アーキテクチャで最大オペレーティング システムの仮想アドレス空間にアクセスできます (SQL Server Standard Edition では最大 128 GB がサポートされます)。 IA64 アーキテクチャでは、制限は 7 TB (SQL Server 2012 (11.x) 以降ではサポートされていません) でした。 詳細については、「 Windows のメモリ制限 」を参照してください。
Windows 拡張機能 (AWE) メモリのアドレス指定
アドレス ウィンドウ拡張機能 (AWE) と AWE で必要なメモリ内のページのロック (LPIM) 特権を使用すると、仮想メモリの少ない条件下で、ほとんどのプロセス メモリSQL Server物理 RAM でロックされた状態を維持できます。 これは、32 ビットと 64 ビットの両方の AWE 割り当てで発生します。 メモリのロックは、AWE メモリがメモリのページングを制御する Windows の仮想メモリ マネージャーを経由しないために発生します。 AWE メモリ割り当て API には、 メモリ内のロック ページ (SeLockMemoryPrivilege) 特権が必要です。 「AllocateUserPhysicalPages notes」を参照してください。 したがって、AWE API を使用する主な利点は、システムにメモリ不足がある場合にほとんどのメモリを RAM に保持することです。 SQL Serverで AWE を使用できるようにする方法については、「メモリ内のページをロックする」オプションを参照してください。
LPIM が許可されている場合は、既定値の 2,147,483,647 MB のままにするのではなく、 max server memory (MB) を特定の値に設定することを強くお勧めします。 詳細については、「 サーバー メモリ サーバーの構成: オプションを手動で設定 する」および「 メモリ内のページをロックする (LPIM)」を参照してください。
LPIM が有効になっていない場合、SQL Serverは従来のメモリの使用に切り替わります。OS メモリ不足の場合は、エラー ログにエラー 17890 が報告されることがあります。 エラーは次の例のようになります。
A significant part of SQL Server process memory has been paged out. This may result in a performance degradation. Duration: #### seconds. Working set (KB): ####, committed (KB): ####, memory utilization: ##%.
SQL Server 2012 (11.x) 以降のメモリ管理の変更
以前のバージョンのSQL Serverでは、5 つの異なるメカニズムを使用してメモリ割り当てが行われました。
- SPA (Single-Page Allocator/単一ページ アロケータ) 。SQL Server プロセスで 8 KB 以下のメモリ割り当てのみ含む。 構成オプションの max server memory (MB) と min server memory (MB) によって、SPA が利用する物理メモリの上限が決められていました。 同時にバッファー プールが SPA のメカニズムであり、これが単一ページ割り当てを最も多く利用していました。
- MPA (Multi-Page Allocator/複数ページ アロケータ) 。8 KB より多くを要求するメモリ割り当て用。
- CLR アロケータ。CLR 初期化中に作成される SQL CLR ヒープとそのグローバル割り当てを含む。
- SQL Server プロセスの スレッド スタック のメモリ割り当て。
- DWA (Direct Windows allocations/直接 Windows 割り当て) 。Windows に直接行われるメモリ割り当て要求。 モジュールによって行われ、SQL Server プロセスに読み込まれる、Windows のヒープ使用量と直接仮想割り当てが含まれます。 このようなメモリ割り当ての例としては、たとえば、拡張ストアド プロシージャ DLL からの割り当て、オートメーション プロシージャ (sp_OA 呼び出し) で作成されたオブジェクト、リンク サーバー プロバイダーからの割り当てがあります。
SQL Server 2012 (11.x) 以降では、Single-Page割り当て、マルチページ割り当て、CLR 割り当ては、すべて "任意のサイズ" ページ アロケーターに統合され、最大サーバー メモリ (MB) と最小サーバー メモリ (MB) 構成オプションによって制御されるメモリ制限に含まれます。 この変更によって、SQL Server メモリ マネージャーを通過するすべてのメモリ要件において、より正確にサイズを調整できるようになりました。
重要
SQL Server 2012 (11.x) 以降にアップグレードした後、現在の最大サーバー メモリ (MB) と最小サーバー メモリ (MB) の構成を慎重に確認してください。 これは、SQL Server 2012 (11.x) 以降は、以前のバージョンに比べ、このような構成に含まれるメモリ割り当てが多くなっているためです。 これらの変更は、2012 SQL Server 2012 (11.x) と SQL Server 2014 (12.x) の 32 ビット バージョンと 64 ビット バージョンのSQL Server 2016 (13.x) 以降の両方に適用されます。
次の表は、メモリ割り当ての種類とそれを制御する構成オプションである max server memory (MB) と min server memory (MB) についてまとめたものです。
メモリ割り当ての種類 | SQL Server 2005 (9.x)、SQL Server 2008 (10.0.x) および SQL Server 2008 R2 (10.50.x) | SQL Server 2012 (11.x) 以降 |
---|---|---|
単一ページ割り当て | はい | はい。"あらゆるサイズの" ページ割り当てに統合。 |
複数ページ割り当て | いいえ | はい。"あらゆるサイズの" ページ割り当てに統合。 |
CLR 割り当て | いいえ | はい |
スレッド スタック メモリ | いいえ | いいえ |
Windows からの直接割り当て | いいえ | いいえ |
SQL Server 2012 (11.x) 以降では、SQL Serverは最大サーバー メモリ (MB) 設定で指定された値よりも多くのメモリを割り当てる可能性があります。 この動作は、サーバー メモリの合計 (KB) の値が、maxserver memory (MB) で指定されているターゲット サーバー メモリ (KB) 設定に既に達している場合に発生する可能性があります。 メモリの断片化によって、複数ページ メモリ要求 (8 KB 超) を満たすだけの連続した空き容量がない場合、SQL Server はメモリ要求を拒否せず、オーバーコミットを実行できます。
この割り当ての実行直後、バックグラウンド タスクのリソース モニターがすべてのメモリ コンシューマーに信号を送り、割り当てられているメモリの解放を求め、Total Server Memory (KB) が Target Server Memory (KB) 仕様を下回るようにします。 そのため、SQL Serverメモリ使用量が、最大サーバー メモリ (MB) 設定を一時的に超える可能性があります。 この場合、サーバー メモリの合計 (KB) パフォーマンス カウンターの読み取りは、最大サーバー メモリ (MB) とターゲット サーバー メモリ (KB) の設定を超えます。
この動作は通常、次の操作中に観察されます。
- 大規模な列ストア インデックス クエリ
- 行ストア クエリでの大規模なバッチ モード
- 大量のメモリを使用してハッシュ操作と並べ替え操作を実行する列ストア インデックス (re)ビルド
- 大きなメモリ バッファーを必要とするバックアップ操作
- 大きな入力パラメーターを格納する必要があるトレース操作
SQL Server 2012 (11.x) 以降のmemory_to_reserveに対する変更
以前のバージョンのSQL Serverでは、SQL Server メモリ マネージャーは、マルチページ アロケーター (MPA)、CLR アロケーター、SQL Server プロセス内のスレッド スタックのメモリ割り当て、およびダイレクト Windows 割り当て (DWA) で使用するために、プロセス仮想アドレス空間 (VAS) の一部を確保しました。 仮想アドレス空間のこの部分は、"Mem-To-Leave" または "non-Buffer Pool" 領域とも呼ばれています。
これらの割り当て用に予約されている仮想アドレス空間は、 memory_to_reserve 構成オプションによって決まります。 SQL Server で使用される初期値は 256 MB です。
"任意のサイズ" ページ アロケーターは 8 KB を超える割り当ても処理するため、 memory_to_reserve 値にはマルチページ割り当ては含まれません。 この変更を除き、他のすべてはこの構成オプションと引き続き同じになります。
次の表は、メモリ割り当ての種類とそれが適用される、SQL Server プロセスの仮想アドレス空間の memory_to_reserve 領域についてまとめたものです。
メモリ割り当ての種類 | SQL Server 2005 (9.x)、SQL Server 2008 (10.0.x) および SQL Server 2008 R2 (10.50.x) | SQL Server 2012 (11.x) 以降 |
---|---|---|
単一ページ割り当て | いいえ | いいえ。"あらゆるサイズの" ページ割り当てに統合。 |
複数ページ割り当て | はい | いいえ。"あらゆるサイズの" ページ割り当てに統合。 |
CLR 割り当て | はい | はい |
スレッド スタック メモリ | はい | はい |
Windows からの直接割り当て | はい | はい |
動的メモリ管理
SQL Server データベース エンジン の既定のメモリ管理動作では、システムでメモリ不足を発生させることなく、必要な量のメモリを獲得します。 SQL Server データベース エンジンでは、Microsoft Windows の Memory Notification API を使用してこれを実現しています。
メモリを動的に使用する場合、 SQL Server はシステムに定期的にクエリして、メモリの空き容量を確認します。 このようにメモリの空き容量を維持することによって、オペレーティング システム (OS) のページングが防止されます。 空きメモリが少ない場合、 SQL Server は OS に対してメモリを解放します。 空きメモリが多い場合、 SQL Server はより多くのメモリを割り当てることができます。 SQL Serverは、ワークロードに必要なメモリが増える場合にのみメモリを追加します。保存中のサーバーは、仮想アドレス空間のサイズを増やしません。 SQL Serverが動的メモリ管理を使用しているときに、タスク マネージャーとパフォーマンス モニターが使用可能なメモリの着実な減少を示している場合は、これが既定の動作であり、メモリ リークとして認識されるべきではありません。
max server memory は、SQL Server のメモリ割り当て、コンパイル メモリ、すべてのキャッシュ (バッファー プールを含む)、クエリ実行メモリ許可、ロック マネージャー メモリ、CLR1 メモリ (基本的に、 sys.dm_os_memory_clerks で見つかったメモリ クラーク) を制御します。
1SQL Server 2012 (11.x) 以降、CLR メモリは max_server_memory 割り当ての下で管理されます。
次のクエリでは、現在割り当てられているメモリに関する情報を返します。
SELECT
physical_memory_in_use_kb/1024 AS sql_physical_memory_in_use_MB,
large_page_allocations_kb/1024 AS sql_large_page_allocations_MB,
locked_page_allocations_kb/1024 AS sql_locked_page_allocations_MB,
virtual_address_space_reserved_kb/1024 AS sql_VAS_reserved_MB,
virtual_address_space_committed_kb/1024 AS sql_VAS_committed_MB,
virtual_address_space_available_kb/1024 AS sql_VAS_available_MB,
page_fault_count AS sql_page_fault_count,
memory_utilization_percentage AS sql_memory_utilization_percentage,
process_physical_memory_low AS sql_process_physical_memory_low,
process_virtual_memory_low AS sql_process_virtual_memory_low
FROM sys.dm_os_process_memory;
スタック サイズ
スレッド スタック 1、CLR 2、拡張プロシージャ .dll ファイル、分散クエリによって参照される OLE DB プロバイダー、Transact-SQL ステートメントで参照されるオートメーション オブジェクト、および非SQL Server DLL によって割り当てられたメモリは、最大サーバー メモリ (MB) によって制御されません。
1 現在のホスト内の特定の数のアフィニティ CPU に対して計算される既定のワーカー スレッドについては、 max worker threads サーバー構成オプションを構成する方法に関する記事を参照してください。 SQL Server スタックのサイズは次のようになります。
SQL Server アーキテクチャ | OS アーキテクチャ | スタック サイズ |
---|---|---|
x86 (32 ビット) | x86 (32 ビット) | 512 KB |
x86 (32 ビット) | x64 (64 ビット) | 768 KB |
x64 (64 ビット) | x64 (64 ビット) | 2048 KB |
IA64 (Itanium) | IA64 (Itanium) | 4096 KB |
2SQL Server 2012 (11.x) 以降、CLR メモリは max_server_memory 割り当ての下で管理されます。
SQL Serverは、メモリ通知 API QueryMemoryResourceNotification を使用して、SQL Server メモリ マネージャーがメモリを割り当ててメモリを解放できるタイミングを決定します。
SQL Serverが開始されると、システム上の物理メモリの量、サーバー スレッドの数、さまざまなスタートアップ パラメーターなど、いくつかのパラメーターに基づいてバッファー プールの仮想アドレス空間のサイズが計算されます。 SQL Server では、計算された量のプロセス仮想アドレス空間をバッファー プール用に予約しますが、現在の負荷に必要な量だけ物理メモリを獲得 (コミット) します。
インスタンスでは、ワークロードのサポートに必要なメモリを獲得し続けます。 多くのユーザーが接続してクエリを実行すると、オンデマンドで SQL Server により多くの物理メモリが割り当てられます。 SQL Server インスタンスは、最大サーバー メモリ (MB) の割り当てターゲットに達するか、または OS が空きメモリの過剰がないことを示すまで物理メモリを取得し続けます。最小サーバー メモリ設定を超えるとメモリが解放され、OS は空きメモリが不足していることを示します。
SQL Serverのインスタンスが動作しているコンピューター上で他のアプリケーションを起動すると、メモリを消費し、物理メモリの空き領域が SQL Server の目標よりも少なくなります。 SQL Server のインスタンスでは、メモリの消費を調整します。 他のアプリケーションが停止され、使用可能なメモリが増えると、 SQL Server のインスタンスはメモリ割り当てのサイズを大きくします。 SQL Server は、数 MB のメモリの解放および獲得を毎秒行うことができるため、メモリ割り当ての変更に迅速に対応できます。
最小および最大サーバー メモリの効果
構成オプションの min server memory と max server memory によって、データベース エンジン のバッファー プールとその他のキャッシュで使用されるメモリ量の上限と下限が決められます。 バッファー プールは、最小サーバー メモリで指定されたメモリ量をすぐに取得しません。 バッファー プールは、初期化に必要なメモリのみで起動します。 SQL Server データベース エンジンのワークロードが増えるにしたがって、そのワークロードに対応するために必要なメモリを獲得し続けます。 バッファー プールは、最小サーバー メモリで指定された量に達するまで、取得したメモリを解放しません。 メモリ容量が min server memory に達すると、バッファー プールは標準アルゴリズムを使用して、必要に応じてメモリ容量を獲得または解放します。 唯一の違いは、バッファー プールが最小サーバー メモリで指定されたレベルを下回るメモリ割り当てを削除せず、 最大サーバー メモリ (MB) で指定されたレベルよりも多くのメモリを取得しないということです。
Note
プロセスとしてSQL Serverは、max server memory (MB) オプションで指定されたよりも多くのメモリを取得します。 内部コンポーネントも外部コンポーネントも、バッファー プール外にメモリ容量を割り当てることができます。この場合は、メモリ容量が余分に消費されますが、通常、SQL Server によって消費されるメモリ容量の最大部分は、バッファー プールに割り当てられたメモリ容量が占めます。
SQL Server データベース エンジンが獲得するメモリ容量は、そのインスタンスのワークロードに完全に依存します。 多くの要求を処理していないSQL Server インスタンスが、最小サーバー メモリに到達しない可能性があります。
最小サーバー メモリと最大サーバー メモリ (MB) の両方に同じ値が指定されている場合、SQL Server データベース エンジンに割り当てられたメモリがその値に達すると、SQL Server データベース エンジンはバッファー プールのメモリの動的解放と取得を停止します。
他のアプリケーションが頻繁に停止または起動されるコンピューター上で SQL Server のインスタンスが動作している場合、 SQL Server のインスタンスによるメモリの割り当てと解放により、他のアプリケーションの起動時間が遅くなることがあります。 SQL Server が、1 つのコンピューター上で動作している複数のサーバー アプリケーションのうちの 1 つであるときも、 SQL Serverに割り当てるメモリ量をシステム管理者が制御しなければならない場合があります。 このような場合は、最小サーバー メモリと最大サーバー メモリ (MB) オプションを使用して、SQL Serverが使用できるメモリの量を制御できます。 min server memory と max server memory は MB 単位で指定されます。 これらのメモリ構成の設定方法に関する推奨事項などの詳細については、「サーバー メモリの構成オプション」を参照してください。
SQL Server オブジェクトの仕様で使用されるメモリ
次の一覧で、 SQL Serverの各オブジェクトによって使用されるおおよそのメモリ量について説明します。 表示されている金額は概算であり、環境とオブジェクトの作成方法によって異なります。
- ロック (ロック マネージャーにより保守管理):64 バイト + (32 バイト * 所有者数)
- ユーザー接続: 約 (3 * network_packet_size + 94 KB)
ネットワーク パケット サイズは、アプリケーションと データベース エンジン 間の通信に使用される表形式データ ストリーム (TDS) パケットのサイズです。 既定のパケット サイズは 4 KB であり、network packet size 構成オプションによって制御されます。
複数のアクティブな結果セット (MARS) が有効になっている場合、ユーザー接続は約 (3 + 3 * num_logical_connections) * network_packet_size + 94 KB になります。
min memory per query の効果
min memory per query 構成オプションでは、クエリの実行用に割り当てる最小メモリ容量 (KB 単位) を確定します。 これは、最小メモリ許可とも呼ばれます。 すべてのクエリは、実行を開始するためには、要求された最小メモリをセキュリティで保護できるようになるまで、または query wait サーバー構成オプションで指定された値を超えるまで、待機する必要があります。 このシナリオで累積される待機の種類は です RESOURCE_SEMAPHORE
。
重要
クエリ サーバー構成オプションあたりの最小メモリを高く設定しないでください。特にビジー状態のシステムでは、次のことが発生する可能性があるためです。
- メモリ リソースの競合が増加します。
- 実行時に必要なメモリがこの構成より少ない場合でも、すべての単一クエリのメモリ量を増やすことで、コンカレンシーが低下します。
この構成の使い方の推奨事項については、「min memory per query サーバー構成オプションの構成」を参照してください。
メモリ許可に関する考慮事項
行モードの実行では、最初のメモリ許可をどの条件でも超えることはできません。 ハッシュ操作または並べ替え操作を実行するために、初期のメモリ許可より多くのメモリを必要とする場合、ディスクへの書き込みが行われます。 スピルするハッシュ操作は、 の Workfile tempdb
でサポートされますが、スピルする並べ替え操作は Worktable でサポートされています。
並べ替え操作中に発生するスピルは、 並べ替えの警告と呼ばれます。 並べ替えの警告は、並べ替え操作がメモリに収まらないことを示します。 これには、インデックスの作成に関連する並べ替え操作は含まれません。クエリ内の並べ替え操作 (ステートメントでSELECT
使用される句などORDER BY
) のみが含まれます。
ハッシュ操作中に発生するスピルは、 ハッシュ警告と呼ばれます。 これらは、ハッシュ演算中にハッシュの再帰またはハッシュの中断 (ハッシュの保留) が生じたときに発生します。
- ハッシュ再帰は、ビルド入力が使用可能なメモリに収まらない場合に発生し、個別に処理される複数のパーティションに入力が分割されます。 これらのパーティションのいずれかが使用可能なメモリに収まらない場合は、サブパーティションに分割され、個別に処理されます。 この分割プロセスは、使用できるメモリ内に各パーティションが収まるようになるまで、または最大再帰レベルに到達するまで続きます。
- ハッシュ演算が最大再帰レベルに到達するとハッシュの保留が発生し、パーティション分割された残りのデータを処理するための代替プランに移行されます。 これらのイベントが原因となって、サーバー内のパフォーマンスが低下する可能性があります。
バッチ モード実行の場合、初期のメモリ許可は既定では特定の内部しきい値まで動的に増加することができます。 この動的なメモリ許可メカニズムは、バッチ モードで実行されているハッシュまたは並べ替え操作のメモリ常駐実行を可能にするように設計されています。 これらの操作がまだメモリに収まらない場合は、ディスクにスピルします。
実行モードの詳細については、「クエリ処理アーキテクチャ ガイド」を参照してください。
バッファー管理
SQL Server データベースの主な目的はデータの格納と取得であるため、データベース エンジンの主要な特性は頻繁なディスク I/O ということになります。 ディスク I/O 操作は多くのリソースを消費するうえ、完了するのに比較的長い時間がかかるので、 SQL Server では I/O の効率を上げることに重点を置いています。 バッファー管理は、この効率向上を実現するための重要なコンポーネントです。 バッファー管理コンポーネントは 2 つのメカニズムから構成されています。1 つはデータベース ページに対するアクセスと更新を行うバッファー マネージャーで、もう 1 つはデータベース ファイルの I/O を削減するバッファー キャッシュ (バッファー プール) です。
バッファー管理のしくみ
バッファーはメモリ内の 8 KB のページで、データ ページやインデックス ページと同じサイズです。 したがって、バッファー キャッシュは 8 KB 単位のページに分割されます。 バッファー マネージャーは、データベース ディスク ファイルのデータ ページやインデックス ページをバッファー キャッシュに読み取って、変更されたページをディスクに書き戻すための機能を管理しています。 バッファー マネージャーが別のデータを読み取るためのバッファー領域を必要とするまで、そのページはバッファー キャッシュ内に残ります。 データに変更が加えられた場合だけ、そのデータがディスクに書き戻されます。 バッファー キャッシュ内のデータは、ディスクに書き戻す前に何度でも変更できます。 詳細については、「 ページの読み取り 」および「 ページの書き込み」をご覧ください。
SQL Serverが開始されると、システム上の物理メモリの量、構成された最大サーバー スレッド数、さまざまなスタートアップ パラメーターなど、いくつかのパラメーターに基づいてバッファー キャッシュの仮想アドレス空間のサイズが計算されます。 SQL Server では、この計算された量のプロセス仮想アドレス空間 (メモリ ターゲット) をバッファー キャッシュ用に予約しますが、現在の負荷に必要な量だけ物理メモリを獲得 (コミット) します。 sys.dm_os_sys_info カタログ ビューの committed_target_kb と committed_kb の列に対してクエリを実行すると、メモリ ターゲットとして予約されているページ数と、バッファー キャッシュ内で現在コミットされているページ数をそれぞれ返すことができます。
SQL Server の起動からバッファー キャッシュがメモリ ターゲットを取得するまでの間隔を、割り当て増加といいます。 この間、読み取り要求によって、必要に応じてバッファーが使用されます。 たとえば、1 つの 8 KB ページの読み取り要求が 1 つのバッファー ページに格納されます。 つまり、割り当て増加は、クライアント要求の数や種類によって異なります。 1 ページずつの読み取り要求を 8 ページ分の要求にまとめて変換することで (1 つのエクステントとします)、割り当て増加を高速化しています。 これにより、特に多くのメモリが搭載されたコンピューターでは、割り当て増加が非常に高速に完了します。 ページとエクステントの詳細については、「 ページとエクステントのアーキテクチャ ガイド」を参照してください。
バッファー マネージャーはほとんどのメモリを SQL Server プロセスで使用するので、メモリ マネージャーと連携して他のコンポーネントでバッファーを使用できるようにします。 バッファー マネージャーは主に次のコンポーネントと対話します。
- リソース マネージャー。全体的なメモリ使用量を制御します。32 ビット プラットフォームではアドレス空間の使用量を制御します。
- データベース マネージャーおよび SQL Server オペレーティング システム (SQLOS)。低レベルのファイル I/O 操作を行います。
- ログ マネージャー。先行書き込みログ記録を行います。
サポートされている機能
バッファー マネージャーは、次の機能をサポートしています。
NUMA (non-uniform memory access) に対応しています。 バッファー キャッシュ ページはハードウェア NUMA ノード間に分散されます。そのため、スレッドは外部メモリからではなく、ローカルの NUMA ノードに割り当てられているバッファー ページにアクセスすることができます。
ホット アド メモリをサポートしています。そのため、ユーザーはサーバーを再起動することなく物理メモリを追加できます。
64 ビット プラットフォームの大きなページをサポートしています。 ページのサイズは、Windows のバージョンに固有です。
Note
SQL Server 2012 (11.x) より前のバージョンの場合、SQL Server で大きなページを有効にするには、トレース フラグ 834 が必要です。
バッファー マネージャーは、動的管理ビューを介して公開される追加の診断を提供します。 これらのビューを使用すると、SQL Serverに固有のさまざまなオペレーティング システム リソースを監視できます。 たとえば、sys.dm_os_buffer_descriptors ビューを使用すると、バッファー キャッシュ内のページを監視できます。
ディスク I/O
バッファー マネージャーはデータベースの読み取りと書き込みだけを行います。 他のファイル操作やデータベース操作 (開く、閉じる、拡張、圧縮など) は、データベース マネージャー コンポーネントおよびファイル マネージャー コンポーネントによって実行されます。
バッファー マネージャーによるディスク I/O 操作には、次の特性があります。
- すべての I/O は非同期で実行されます。つまり、呼び出し側スレッドでの処理中でも、I/O 操作はバックグラウンドで進行します。
- アフィニティ I/O オプションが使用されていない限り、呼び出し元のスレッドですべての I/O が発行されます。 affinity I/O mask オプションでは、 SQL Server のディスク I/O が、指定した CPU のサブセットに関連付けられます。 ハイエンドな SQL Server オンライン トランザクション処理 (OLTP) 環境では、この拡張機能により、I/O を発行する SQL Server スレッドのパフォーマンスを向上できます。
- 複数ページの I/O は、スキャッター/ギャザー I/O を使用して実行されます。スキャッター/ギャザー I/O を使用すると、連続しないメモリ領域との間でデータを転送できます。 つまり、 SQL Server は、複数の物理 I/O 要求を回避しながら、バッファー キャッシュをすばやく使用またはフラッシュできます。
実行時間の長い I/O 要求
バッファー マネージャーは未処理状態が 15 秒以上続いた I/O 要求を報告します。 これはシステム管理者が SQL Server の問題か I/O サブシステムの問題かを区別するのに役立ちます。 SQL Server のエラー ログには、次のようなエラー メッセージ 833 が報告および記録されます。
SQL Server has encountered ## occurrence(s) of I/O requests taking longer than 15 seconds to complete on file [##] in database [##] (#). The OS file handle is 0x00000. The offset of the latest long I/O is: 0x00000.
長い I/O は、読み取りまたは書き込みのいずれかです。現在、メッセージに示されていません。 実行時間の長い I/O のメッセージは、警告であってエラーではありません。 SQL Serverに関する問題ではなく、基になる I/O システムに関する問題を示しています。 これらのメッセージが報告されることにより、システム管理者は、 SQL Server の応答時間が遅い原因を追求したり、 SQL Serverの制御の範囲外にある問題を見分けたりするのに役立てることができます。 そのため、アクションは必要ありませんが、システム管理者は、I/O 要求に時間がかかった理由と、時間が正当かどうかを調査する必要があります。
長い I/O 要求の原因
長い I/O メッセージは、I/O が完全にブロックされ、完了しない (失われた I/O と呼ばれる) か、まだ完了していないことを示している可能性があります。 メッセージからどのシナリオが該当するかを確認することはできませんが、I/O が失われるとラッチ タイムアウトが発生することがよくあります。
多くの場合、実行時間の長い I/O は、 SQL Server のワークロードによってディスク サブシステムに過度の負荷がかかっていることを示します。 ディスク サブシステムが不十分だと、次の現象が発生することがあります。
- 負荷の高い SQL Server ワークロード中に、実行時間の長い I/O のメッセージがエラー ログに複数記録される。
- パフォーマンス モニター カウンターには、ディスクの待機時間が長い、ディスク キューが長い、またはディスクのアイドル時間が表示されません。
実行時間の長い I/O は、I/O パス内のコンポーネント (ドライバー、コントローラー、ファームウェアなど) が原因になっている場合もあります。ディスク ヘッドの現在位置の近くにある新しい I/O 要求の処理を優先して、古い I/O 要求の処理を絶えず延期するためです。 読み取り/書き込みヘッドの現在の位置に最も近いものに基づいて要求を優先順位で処理する一般的な手法は、"エレベーターシーク" と呼ばれます。ほとんどの I/O が迅速に処理されているため、パフォーマンス モニター ツールを使用してこれを補強することは困難な場合があります。 実行時間の長い I/O 要求は大容量のシーケンシャル I/O を実行するワークロードによって増大することがあります。たとえば、バックアップおよび復元、テーブル スキャン、並べ替え、インデックスの作成、一括読み込み、ファイルの占有領域の解放処理などがあります。
以前の状態のいずれにも関連していない分離された長い I/O は、ハードウェアまたはドライバーの問題が原因である可能性があります。 システム イベント ログには、問題の診断に役立つ関連イベントが含まれていることがあります。
メモリ不足の検出
メモリ不足は、メモリの不足が原因で発生する状態であり、次の結果を招く可能性があります。
- 余分な I/O の発生 (レイジー ライターの非常にアクティブなバック グラウンド スレッドなど)
- 再コンパイルの比率が高くなる
- クエリの実行時間が長くなる (メモリ許可待機が存在する場合)
- 余分な CPU サイクルが発生する
この状況は、外部的な原因または内部的な原因によって引き起こされる可能性があります。 外部的な原因には次のようなものがあります。
- 使用可能な物理メモリ (RAM) が不足しています。 これにより、システムは現在実行中のプロセスのワーキング セットをトリミングします。結果として、全体的な速度が低下する可能性があります。 SQL Server はバッファー プールのコミット ターゲットを削減し、内部キャッシュのトリミングを頻繁に開始する可能性があります。
- 使用できる全体的なシステム メモリ (システムのページ ファイルを含む) が不足しています。 これにより、システムはメモリの割り当てを失敗する場合があります。現在割り当てられているメモリをページ アウトできないためです。
内部的な原因には次のようなものがあります。
- SQL Server データベース エンジン がメモリ使用量の下限を設定する場合に外部メモリ不足に対応します。
- max server memory 構成の値を手動で縮小することにより、メモリ設定の値が引き下げられました。
- 内部コンポーネントによるいくつかのキャッシュ間のメモリ配分に変更が生じました。
SQL Server データベース エンジン では、動的メモリ管理の一環として、メモリ不足の検出および処理のために専用のフレームワークが実装されます。 このフレームワークには、リソース モニターと呼ばれるバックグラウンド タスクが含まれています。 リソース モニター タスクでは、外部および内部のメモリ インジケーターの状態が監視されます。 これらのインジケーターのいずれかの状態が変化すると、対応する通知が計算され、その通知がブロードキャストされます。 これらの通知は各エンジン コンポーネントからの内部メッセージであり、リング バッファーに格納されます。
次の 2 つのリング バッファーに、動的メモリ管理に関連する情報が保持されます。
- メモリ不足が通知されているかどうかなど、リソース モニターのアクティビティを追跡するリソース モニター リング バッファー。 このリング バッファーには、、
RESOURCE_MEMPHYSICAL_LOW
RESOURCE_MEMPHYSICAL_STEADY
、またはRESOURCE_MEMVIRTUAL_LOW
の現在のRESOURCE_MEMPHYSICAL_HIGH
状態に応じて、状態情報が含まれます。 - 各 Resource Governor リソース プールのメモリ通知のレコードが含まれるメモリ ブローカー リング バッファー。 内部メモリ不足が検出されると、メモリの割り当てを行うコンポーネントに対して、メモリ不足を示す通知がオンになり、キャッシュ間でメモリのバランスをとるためのアクションがトリガーされます。
メモリ ブローカーは、コンポーネントごとにメモリの需要と消費量を監視し、収集した情報に基づいて、これらのコンポーネントの各々に対してメモリの最適な値を算出します。 Resource Governor リソース プールごとにブローカー セットがあります。 この情報は、使用量を必要に応じて拡大または縮小する各コンポーネントにブロードキャストされます。
メモリ ブローカーの詳細については、sys.dm_os_memory_brokers に関するページを参照してください。
エラー検出
データベース ページでは、ページがディスクに書き込まれた時点から再び読み取られるまで、ページの整合性を確保するのに役立つ、ページ保護とチェックサム保護という 2 つの省略可能なメカニズムのいずれかを使用できます。 これらのメカニズムによって、データ ストレージだけでなく、ハードウェア コンポーネント (コントローラー、ドライバー、ケーブルなど)、およびオペレーティング システムに至るまで、個々の正確性を検証するための独立した手段が可能になります。 この保護はディスクに書き込む直前にページに追加され、ディスクから読み取られた後で検証されます。
SQL Server は、チェックサム、破損ページ、またはその他の I/O エラーで読み取りに失敗した場合、その読み取りを 4 回再試行します。 いずれかの再試行で読み取りに成功した場合には、エラー ログにメッセージが書き込まれ、その読み取りを起動したコマンドは続行されます。 再試行が失敗した場合には、そのコマンドはエラー メッセージ 824 で失敗します。
使用されている種類のページ保護は、ページが含まれているデータベースの属性です。 チェックサム保護は SQL Server 2005 (9.x) 以降で作成されたデータベースの既定の保護です。 ページ保護メカニズムはデータベース作成時に指定され、 を使用 ALTER DATABASE SET
して変更できます。 sys.databases カタログ ビューの列または DATABASEPROPERTYEX 関数の プロパティに対してクエリをIsTornPageDetectionEnabled
実行page_verify_option
することで、現在のページ保護設定を確認できます。
Note
ページ保護の設定が変更されたとき、新しい設定がデータベース全体にすぐに反映されるわけではありません。 個々のページの出力時に、現在のデータベースの保護レベルがそのページに適用されます。 つまり、データベースはそれぞれ保護の種類が異なるページで構成されている場合があります。
破損ページ保護
SQL Server 2000 (8.x) で導入されたページ保護は、主に電源障害によるページ破損を検出する方法です。 たとえば、予期しない電源障害でページの一部だけがディスクに書き込まれた状態になったとします。 破損ページ保護が使用されているとき、ディスクへのページ書き込み時に、8 KB のデータベース ページ内の 512 バイトのセクターごとに、特定の 2 ビット署名パターンがデータベース ページ ヘッダーに格納されます。
そのページがディスクから読み取られるときに、ページ ヘッダーに保存されている各セクターの破損ビットと、実際のページ セクター情報とが比較されます。 署名パターンはバイナリ 01
と 10
書き込みの間で交互に行われるので、セクターの一部だけがディスクに変換したタイミングを常に確認できます。ページが後で読み取られるときにビットが間違った状態にある場合、ページが誤って書き込まれ、ページが破損することが検出されます。 ページの破損検出では、最小限のリソースが使用されます。ただし、ディスク ハードウェアの障害によって発生したすべてのエラーが検出されるわけではありません。 ページの破損検出の設定については、「 ALTER DATABASE SET Options (Transact-SQL)」を参照してください。
チェックサム保護
チェックサム保護は、SQL Server 2005 (9.x) から導入されたもので、今まで以上に強力なデータ整合性チェックを提供します。 チェックサムは各ページに書き込まれるデータから算出され、ページ ヘッダーに書き込まれます。 ページにチェックサムが書き込まれている場合は、そのページをディスクから読み取るたびにデータのチェックサムが再計算されます。そして、新しく計算されたチェックサムと、現在書き込まれているチェックサムが異なる場合は、エラー 824 が生成されます。 チェックサム保護はページの各バイトの影響を受けるので、破損ページ保護よりも多くのエラーをキャッチできますが、使用されるリソースがやや多くなります。
チェックサムが有効になっている場合、電源障害、欠陥のあるハードウェアやソフトウェアが原因で発生するエラーは、バッファー マネージャーがディスクからページを読み取るたびに検出できます。 チェックサムの設定については、「 ALTER DATABASE SET Options (Transact-SQL)」を参照してください。
重要
ユーザーまたはシステム データベースが SQL Server 2005 (9.x) 以降にアップグレードされると、PAGE_VERIFY値 (NONE
または TORN_PAGE_DETECTION
) が保持されます。 を使用 CHECKSUM
することを強くお勧めします。 TORN_PAGE_DETECTION
使用するリソースは少なくなりますが、保護のサブセットは最小限に CHECKSUM
抑えられます。
統一されていないメモリ アクセスについて
SQL Server は Non-Uniform Memory Access (NUMA) に対応しているので、特殊な構成を行わなくても NUMA ハードウェアで適切に実行されます。 プロセッサのクロック速度や数が増加するにつれて処理能力が向上しますが、その一方で、向上した能力の活用に必要となるメモリの待機時間を減らすことが困難になります。 ハードウェア ベンダーはメモリの待機時間をなくすために、大容量の L3 キャッシュを搭載していますが、この解決策にも限界があります。 この問題に対する、拡張性に優れた解決方法が NUMA アーキテクチャです。
SQL Server は、アプリケーションを変更しなくても NUMA ベースのコンピューターを活用できるように設計されています。 詳細については、「SQL Server を構成する方法」をご覧ください。
メモリ オブジェクトの動的パーティション
SQL Server のメモリ オブジェクトと呼ばれるヒープ アロケーターを使用すると、データベース エンジン で、ヒープからメモリを割り当てることができます。 これらは sys.dm_os_memory_objects DMV を使用して追跡できます。
CMemThread とは、複数のスレッドから同時にメモリを割り当てることを可能にするスレッドセーフなメモリ オブジェクトの種類です。 追跡を正確に行うために、CMemThread オブジェクトは、同期コンストラクト (ミューテックス) に依存し、一度に 1 つのスレッドのみで重要な情報が確実に更新されるようになっています。
Note
CMemThread オブジェクトの種類は、データベース エンジン コード ベース全体でさまざまな割り当てに使用され、ノードごとまたは CPU ごとにグローバルに分割することができます。
ただし、ミューテックスを使用すると、多数のスレッドが同じメモリ オブジェクトから同時性の高い方法で割り当てられる場合に競合が発生する可能性があります。 したがって、SQL Server にはパーティション分割されたメモリ オブジェクト (PMO) という概念があり、各パーティションはそれぞれ 1 つの CMemThread オブジェクトによって表されます。 メモリ オブジェクトのパーティション分割は静的に定義され、作成後に変更することはできません。 メモリ割り当てパターンは、ハードウェアやメモリの使用状況などの側面に大きく左右されるので、完全なパーティション分割パターンを事前に取得することは不可能です。
ほとんどの場合、1 つのパーティションを使用するだけで十分ですが、一部のシナリオでは競合が発生する可能性があり、これは高度にパーティション分割されたメモリ オブジェクトでのみ防止できます。 パーティションが増えると、他の非効率性が発生し、メモリの断片化が増加する可能性があるため、各メモリ オブジェクトをパーティション分割することは望ましくありません。
Note
SQL Server 2016 (13.x) より前は、トレース フラグ 8048 を使用して、ノードベースの PMO を強制的に CPU ベースの PMO にすることができました。 SQL Server 2014 (12.x) SP2 および SQL Server 2016 (13.x) 以降は、この動作は動的であり、エンジンによって制御されます。
SQL Server 2014 (12.x) SP2 および SQL Server 2016 (13.x) 以降は、データベース エンジン が特定の CMemThread オブジェクトでの競合を動的に検出し、そのオブジェクトをノードごと、または CPU ごとに基づく実装に昇格させることができます。 昇格すると、SQL Server プロセスが再開されるまで、PMO は昇格されたままになります。 CMemThread 競合は、sys.dm_os_wait_stats DMV で高い CMEMTHREAD 待機が発生し、DMV 列 、partition_type
、、exclusive_allocations_count
および waiting_tasks_count
sys.dm_os_memory_objects DMV 列contention_factor
を監視することによって検出できます。