SQL Serverのメモリ不足またはメモリ不足の問題のトラブルシューティング

現象

SQL Serverは、複雑でリッチな機能セットに対応する複雑なメモリ アーキテクチャを使用します。 さまざまなメモリニーズがあるため、メモリ消費とメモリ不足の原因となる可能性があります。

SQL Serverのメモリ不足を示す一般的なエラーがあります。 エラーの例を次に示します。

  • 701: クエリを実行するのに十分なメモリを割り当てられません。
  • 802: バッファー プール内のページ (データまたはインデックス ページ) を割り当てるためにメモリを取得できない。
  • 1204: ロックのメモリを割り当てに失敗しました。
  • 6322: XML パーサーのメモリを割り当てに失敗しました。
  • 6513:メモリ不足のため CLR を初期化できない。
  • 6533: メモリ不足のため、AppDomain がアンロードされました。
  • 8318: メモリ不足のため SQL パフォーマンス カウンターを読み込めませんでした。
  • 8356 または 8359: メモリ不足のため、ETW または SQL トレースの実行に失敗します。
  • 8556: メモリ不足のため MSDTC を読み込めませんでした。
  • 8645: メモリ許可のメモリがないためにクエリを実行できない (並べ替えとハッシュ) 詳細については、「エラー 8645 SQL Serverトラブルシューティングする方法」を参照してください。
  • 8902: DBCC の実行中にメモリを割り当てに失敗しました。
  • 9695 または 9696: Service Broker 操作のメモリ割り当てに失敗しました。
  • 17131 または 17132: メモリ不足によるサーバーの起動エラー。
  • 17890: OS によってページアウトされている SQL メモリが原因でメモリを割り当てに失敗しました。
  • 22986 または 22987: メモリ不足によるデータ キャプチャエラーを変更します。
  • 25601: Xevent エンジンがメモリ不足です。
  • 26053: SQL ネットワーク インターフェイスは、メモリ不足のため初期化に失敗します。
  • 30085、30086、30094: メモリ不足のため SQL フルテキスト操作が失敗します。

原因

多くの要因によってメモリ不足が発生する可能性があります。 このような要因としては、オペレーティング システムの設定、物理メモリの可用性、SQL Server内のメモリを使用するコンポーネント、現在のワークロードのメモリ制限などがあります。 ほとんどの場合、メモリ不足エラーで失敗したクエリがこのエラーの原因ではありません。 全体として、原因は次の 3 つのカテゴリに分類できます。

原因 1: 外部または OS のメモリ負荷

外部負荷とは、プロセス外のコンポーネントから発生するメモリ使用率が高く、SQL Serverのメモリ不足につながることを指します。 システム上の他のアプリケーションがメモリを消費していて、メモリの可用性が低くなっているかどうかを調べる必要があります。 SQL Serverは、メモリ使用量を削減することで OS メモリの負荷に対応するように設計されたごく少数のアプリケーションの 1 つです。 つまり、アプリケーションまたはドライバーがメモリを要求した場合、OS はすべてのアプリケーションに信号を送信してメモリを解放し、SQL Serverは独自のメモリ使用量を減らすことで応答します。 他のアプリケーションでは、その通知をリッスンするように設計されていないため、応答するアプリケーションはほとんどありません。 そのため、SQL Serverがメモリ使用量の削減を開始すると、そのメモリ プールは減少し、メモリを必要とするコンポーネントが取得できない可能性があります。 その結果、701 またはその他のメモリ関連のエラーが発生し始めます。 SQL がメモリを動的に割り当てて解放する方法の詳細については、「SQL Serverメモリ アーキテクチャ」を参照してください。 問題の詳細な診断と解決策については、この記事の「外部メモリの負荷」を参照してください。

OS メモリの負荷を引き起こす可能性がある問題には、次の 3 つのカテゴリがあります。

  • アプリケーション関連の問題: 1 つまたは複数のアプリケーションが一緒に使用可能な物理メモリを使い果たす。 OS は、メモリの解放を試みることで、リソースに対する新しいアプリケーション要求に応答します。 一般的な方法は、どのアプリケーションがメモリを使い果たしているかを見つけ、RAM の枯渇につながることなくメモリのバランスを取るために必要な手順を実行することです。
  • デバイス ドライバーの問題: ドライバーがメモリ割り当て関数を誤って呼び出した場合、デバイス ドライバーによってすべてのプロセスのワーキング セット ページングが発生する可能性があります。
  • オペレーション システムの製品に関する問題。

これらの手順とトラブルシューティング手順の詳細については、「 MSSQLSERVER_17890」を参照してください。

原因 2: 内部メモリ不足、SQL Serverから発生しない

内部メモリ負荷とは、SQL Server プロセス内の要因によって引き起こされるメモリの可用性の低下を指します。 SQL Server プロセス内で実行される可能性のある一部のコンポーネントは、SQL Server エンジンの "外部" です。 たとえば、リンク サーバー、SQLCLR プロシージャまたは関数、拡張プロシージャ (XP)、OLE Automation () などの OLE DB プロバイダー (sp_OA*DLL) などがあります。 その他には、監視目的でプロセス内に DLL を挿入するウイルス対策プログラムやその他のセキュリティ プログラムが含まれます。 これらのコンポーネントの問題や設計が不十分な場合は、メモリ消費量が大きくなる可能性があります。 たとえば、リンク サーバーが外部ソースから SQL Server メモリに 2,000 万行のデータをキャッシュするとします。 SQL Serverに関する限り、メモリの使用量が多いとメモリ 担当者は報告しませんが、SQL Server プロセス内で消費されるメモリは高くなります。 たとえば、リンク サーバー DLL からのこのメモリの増加により、SQL Serverがメモリ使用量の削減を開始し (上記を参照)、SQL Server内のコンポーネントのメモリ条件が低くなり、メモリ不足エラーが発生します。 この問題に関する詳細な診断と解決策については、SQL Serverからの内部メモリ不足に関するページを参照してください。

注:

SQL Server プロセス空間で使用されるいくつかの Microsoft DLL (MSOLEDBSQLSQL Native Client など) は、レポートと割り当てのためにSQL Serverメモリ インフラストラクチャとインターフェイスできます。 を実行 select * from sys.dm_os_memory_clerks where type='MEMORYCLERK_HOST' してそれらの一覧を取得し、一部の割り当てについてそのメモリ消費量を追跡できます。

原因 3: SQL Server コンポーネントからの内部メモリ負荷

SQL Server エンジン内のコンポーネントからの内部メモリ不足によって、メモリ不足エラーが発生する可能性もあります。 SQL Serverでメモリを割り当てるメモリ クラークを介して追跡されるコンポーネントは数百あります。 この問題を解決するには、最大のメモリ割り当てを担当するメモリ クラークを特定する必要があります。 たとえば、メモリの書記に大きなメモリ割り当てが表示されている場合 OBJECTSTORE_LOCK_MANAGER は、ロック マネージャーが大量のメモリを消費している理由を理解する必要があります。 多くのロックを取得するクエリがある場合があります。 これらのクエリを最適化するには、インデックスを使用するか、ロックを長時間保持するトランザクションを短縮するか、ロックエスカレーションが無効になっているかどうかを確認します。 各メモリ 書記またはコンポーネントには、メモリにアクセスして使用する独自の方法があります。 詳細については、「 メモリ 書記の種類 とその説明」を参照してください。 この問題に関する詳細な診断と解決策については、「SQL Server エンジンによる内部メモリ使用量」を参照してください。

メモリ圧力の種類の視覚的表現

次のグラフは、SQL Serverのメモリ不足状態につながる可能性がある圧力の種類を示しています。

メモリ圧力の種類のスクリーンショット。

トラブルシューティング データを収集するための診断ツール

次の診断ツールを使用して、トラブルシューティング データを収集できます。

パフォーマンス モニター

パフォーマンス モニターで次のカウンターを構成して収集します。

  • Memory:Available MBytes
  • Process:Working Set
  • Process:Private Bytes
  • SQL Server:Memory Manager: (すべてのカウンター)
  • SQL Server:Buffer Manager: (すべてのカウンター)

DMV または DBCC MEMORYSTATUS

sys.dm_os_memory_clerksまたは DBCC MEMORYSTATUS を使用して、SQL Server内の全体的なメモリ使用量を確認できます。

SSMS のメモリ消費標準レポート

SQL Server Management Studioでメモリ使用量を表示します。

  1. SQL Server Management Studio起動し、サーバーに接続します。
  2. オブジェクト エクスプローラーで、SQL Server インスタンス名を右クリックします。
  3. コンテキスト メニューで、[レポート] [標準レポート>>] [メモリ使用量] の選択を行います。

PSSDiag または SQL LogScout

これらのデータ ポイントをキャプチャする別の自動化された方法は、 PSSDiagSQL LogScout などのツールを使用することです。

  • PSSDiag を使用する場合は、 Perfmon コレクターと カスタム診断\SQL メモリ エラー コレクターをキャプチャするように構成します。

  • SQL LogScout を使用する場合は、 メモリ シナリオをキャプチャするように構成します。

次のセクションでは、各シナリオ (外部または内部のメモリ負荷) の詳細な手順について説明します。

トラブルシューティング手法

メモリ不足エラーが発生する場合や短時間発生する場合は、それ自体を解決する有効期間の短いメモリの問題が発生する可能性があります。 このような場合は、アクションを実行する必要がない場合があります。 ただし、エラーが複数の接続で複数回発生し、数秒以上持続する場合は、次のセクションの診断と解決策に従って、メモリ エラーをさらにトラブルシューティングします。

外部メモリの負荷

SQL Server プロセスの外部でシステムのメモリ不足状態を診断するには、次の方法を使用します。

  • パフォーマンス モニター カウンターを収集します。 SQL Server以外のアプリケーションまたはサービスがこのサーバーのメモリを消費しているかどうかを調べるには、次のカウンターを参照してください。

    • Memory:Available MBytes
    • Process:Working Set
    • Process:Private Bytes

    PowerShell を使用した Perfmon ログ収集の例を次に示します。

    clear
    $serverName = $env:COMPUTERNAME
    $Counters = @(
       ("\\$serverName" +"\Memory\Available MBytes"),
       ("\\$serverName" +"\Process(*)\Working Set"),
       ("\\$serverName" +"\Process(*)\Private Bytes")
    )
    
    Get-Counter -Counter $Counters -SampleInterval 2 -MaxSamples 1 | ForEach-Object  {
    $_.CounterSamples | ForEach-Object   {
       [pscustomobject]@{
          TimeStamp = $_.TimeStamp
          Path = $_.Path
          Value = ([Math]::Round($_.CookedValue, 3)) }
    }
    }
    
  • システム イベント ログを確認し、メモリ関連のエラー (仮想メモリの不足など) を探します。

  • アプリケーション関連のメモリの問題については、アプリケーション イベント ログを確認してください。

    次に示すのは、PowerShell スクリプトの例で、システム およびアプリケーション イベント ログに対して キーワード (keyword) "メモリ" のクエリを実行するスクリプトです。検索に "resource" などの他の文字列を自由に使用してください。

    Get-EventLog System -ComputerName "$env:COMPUTERNAME" -Message "*memory*"
    Get-EventLog Application -ComputerName "$env:COMPUTERNAME" -Message "*memory*"
    
  • 重要度の低いアプリケーションまたはサービスのコードまたは構成の問題に対処して、メモリ使用量を減らします。

  • SQL Server以外のアプリケーションがリソースを消費している場合は、これらのアプリケーションを停止または再スケジュールするか、別のサーバーで実行することを検討してください。 これらの手順により、外部メモリの負荷が除去されます。

SQL Serverからの内部メモリ不足

SQL Server内のモジュール (DLL) によって発生する内部メモリ負荷を診断するには、次の方法を使用します。

  • SQL Serverがメモリ内のロックされたページ (AWE API) を使用しない場合、そのメモリのほとんどは、パフォーマンス モニターの Process:Private Bytes カウンター (SQLServrインスタンス) に反映されます。 SQL Server エンジン内からの全体的なメモリ使用量は、SQL Server:Memory Manager: Total Server Memory (KB) カウンターに反映されます。 値 Process:Private BytesSQL Server:Memory Manager: Total Server Memory (KB) の間に大きな違いがある場合、その違いは DLL (リンク サーバー、XP、SQLCLR など) から発生する可能性があります。 たとえば、プライベート バイトが 300 GB で、サーバー メモリの合計が 250 GB の場合、プロセス内のメモリ全体の約 50 GB は、SQL Server エンジンの外部から送信されます。

  • SQL Serverがメモリ内のロックされたページ (AWE API) を使用している場合、パフォーマンス モニターは個々のプロセスのメモリ使用量を追跡する AWE カウンターを提供しないため、問題を特定するのが難しくなります。 SQL Server エンジン内の全体的なメモリ使用量は、SQL Server:Memory Manager: Total Server Memory (KB) カウンターに反映されます。 一般的な プロセス:プライベート バイト の値は、全体で 300 MB から 1 ~ 2 GB の間で異なる場合があります。 この一般的な使用を超えて Process:Private Bytes が大幅に使用されている場合、違いは DLL (リンク サーバー、XP、SQLCLR など) から発生する可能性があります。 たとえば、プライベート バイト カウンターが 4 から 5 GB で、SQL Serverがメモリ内のロックされたページ (AWE) を使用している場合、プライベート バイトの大部分がSQL Server エンジンの外部から送信される可能性があります。 これは近似手法です。

  • Tasklist ユーティリティを使用して、SQL Server領域内に読み込まれる DLL を特定します。

    tasklist /M /FI "IMAGENAME eq sqlservr.exe"
    
  • 次のクエリを使用して、読み込まれたモジュール (DLL) を調べ、予期しない何かがあるかどうかを確認することもできます。

    SELECT * FROM sys.dm_os_loaded_modules
    
  • リンク サーバー モジュールが大量のメモリ消費を引き起こしている可能性がある場合は、[イン プロセスを許可する] オプションを無効にして、プロセスが不足するように構成できます。 詳細については、「 リンク サーバーの作成 」を参照してください。 すべてのリンク サーバー OLE DB プロバイダーがプロセスを使い果たさない可能性があります。 詳細については、製品の製造元にお問い合わせください。

  • OLE オートメーション オブジェクト (sp_OA*) が使用されるまれなケースでは、コンテキスト値 4 (ローカル (.exe) OLE サーバーのみを指定することで、SQL Server外のプロセスで実行するようにオブジェクトを構成できます。 詳細については、「 sp_OACreate」を参照してください。

SQL Server エンジンによる内部メモリ使用量

SQL Server エンジン内のコンポーネントからの内部メモリ負荷を診断するには、次の方法を使用します。

  • SQL Serverのパフォーマンス モニター カウンターの収集を開始します。SQL Server:Buffer ManagerSQL Server: Memory Manager

  • SQL Server メモリ クラーク DMV を複数回照会して、エンジン内でメモリの消費量が最も多い場所を確認します。

    SELECT pages_kb, type, name, virtual_memory_committed_kb, awe_allocated_kb
    FROM sys.dm_os_memory_clerks
    ORDER BY pages_kb DESC
    
  • または、より詳細な DBCC MEMORYSTATUS 出力と、これらのエラー メッセージが表示されたときに変更される方法を確認することもできます。

    DBCC MEMORYSTATUS
    
  • メモリ クラークの間で明確な違反者を特定する場合は、そのコンポーネントのメモリ消費量の詳細に対処することに重点を置きます。 いくつかの例は次のとおりです。

    • メモリクラーク MEMORYCLERK_SQLQERESERVATIONS がメモリを消費している場合は、巨大なメモリ許可を使用しているクエリを特定し、インデックスを使用して最適化するか、書き換える ( ORDER by削除など)、メモリ付与クエリ ヒントを適用します ( 「min_grant_percentとmax_grant_percentヒント 」を参照してください)。 リソース ガバナー プールを作成して、メモリ許可メモリの使用量を制御することもできます。 メモリ許可の詳細については、「SQL Serverでのメモリ許可によって発生するパフォーマンスの低下またはメモリ不足の問題のトラブルシューティング」を参照してください。
    • 多数のアドホック クエリ プランがキャッシュされている場合、 CACHESTORE_SQLCP メモリ 書記は大量のメモリを使用します。 クエリ プランを再利用できないパラメーター化されていないクエリを特定し、ストアド プロシージャに変換するか、 を使用するか、パラメーター化を使用sp_executesqlFORCEDしてパラメーター化します。 トレース フラグ 174 を有効にしている場合は、無効にして、これが問題を解決するかどうかを確認できます。
    • オブジェクト プラン のキャッシュ ストア CACHESTORE_OBJCP で大量のメモリが消費されている場合は、大量のメモリを使用しているストアド プロシージャ、関数、またはトリガーを特定し、アプリケーションを再設計する可能性があります。 一般的に、これは、それぞれに数百のプロシージャを含む大量のデータベースまたはスキーマが原因で発生する可能性があります。
    • メモリ 担当者が OBJECTSTORE_LOCK_MANAGER 大きなメモリ割り当てを表示する場合は、多数のロックを適用するクエリを特定し、インデックスを使用して最適化します。 特定の分離レベルでロックが長期間解放されないトランザクションを短縮するか、ロックエスカレーションが無効になっている場合にチェックします。
    • () が非常に大きいTokenAndPermUserStoreselect type, name, pages_kb from sys.dm_os_memory_clerks where name = 'TokenAndPermUserStore'場合は、トレース フラグ 4618 を使用してキャッシュのサイズを制限できます。
    • メモリの書記からMEMORYCLERK_XTP送信 In-Memory OLTP でメモリの問題が発生した場合は、メモリ不足エラーの OLTP とメモリ最適化 tempdb メタデータ (HkTempDB) の In-Memory のメモリ使用量の監視とトラブルシューティングに関するページを参照してください。

メモリを使用可能にする可能性があるクイック リリーフ

次のアクションにより、メモリが解放され、SQL Serverで使用できるようになる場合があります。

メモリ構成設定を変更する

次のSQL Serverメモリ構成パラメーターを確認し、可能な場合は最大サーバー メモリを増やすことを検討してください。

  • 最大サーバー メモリ
  • 最小サーバー メモリ

注:

異常な設定に気付いた場合は、必要に応じて修正し、メモリ要件の増加を考慮してください。 既定の設定は、 サーバー メモリ構成オプションに一覧表示されます。

最大サーバー メモリ (特にメモリ内のロックされたページ) を構成していない場合は、OS のメモリを許可するように特定の値に設定することを検討してください。 「 メモリ内のロックされたページ 」サーバー構成オプションを参照してください。

ワークロードをシステムから変更または移動する

クエリ ワークロードを調査します。同時セッションの数、現在実行中のクエリ、および一時的に停止されたり、別のSQL Serverに移動されたりする可能性のある重要度の低いアプリケーションがあるかどうかを確認します。

読み取り専用ワークロードの場合は、Always On環境の読み取り専用セカンダリ レプリカに移動することを検討してください。 詳細については、「読み取り専用ワークロードをAlways On可用性グループのセカンダリ レプリカにオフロードする」および「Always On可用性グループのセカンダリ レプリカへの読み取り専用アクセスを構成する」を参照してください。

仮想マシンの適切なメモリ構成を確認する

仮想マシン (VM) でSQL Serverを実行している場合は、VM のメモリがオーバーコミットされていないことを確認します。 VM のメモリを構成する方法については、「 仮想化 - メモリのオーバーコミット」と「VM 内でメモリを検出する方法」およびESX/ESXi 仮想マシンのパフォーマンスの問題のトラブルシューティング (メモリオーバーコミット)」を参照してください。

SQL Server内のメモリを解放する

次の 1 つ以上の DBCC コマンドを実行して、いくつかのSQL Serverメモリ キャッシュを解放できます。

  • DBCC FREESYSTEMCACHE

  • DBCC FREESESSIONCACHE

  • DBCC FREEPROCCACHE

サービスSQL Server再起動する

場合によっては、メモリの重大な枯渇に対処する必要があり、SQL Serverクエリを処理できない場合は、サービスの再起動を検討できます。

特定のシナリオにResource Governorを使用することを検討する

Resource Governorを使用している場合は、リソース プールとワークロード グループの設定をチェックして、メモリが過度に制限されていないかどうかを確認することをお勧めします。

物理サーバーまたは仮想サーバーに RAM を追加する

問題が解決しない場合は、さらに調査し、サーバー リソース (RAM) を増やす必要があります。