MSSQLSERVER_701

適用対象:SQL Server

詳細

属性
製品名 SQL Server
イベント ID 701
イベント ソース MSSQLSERVER
コンポーネント SQLEngine
シンボル名 NOSYSMEM
メッセージ テキスト このクエリを実行できるだけのシステム メモリがありません。

注意

この記事では、SQL Server について重点的に説明します。 Azure SQL Database のメモリ不足の問題のトラブルシューティングについて詳しくは、「Azure SQL Database によるメモリ不足エラーのトラブルシューティング」をご覧ください。

説明

エラー 701 は、クエリを実行するのに十分なメモリを割り当てSQL Serverが失敗したときに発生します。 メモリ不足の原因としては、オペレーティング システムの設定、物理メモリの可用性、他のコンポーネントで SQL Server 内のメモリが使用されている、現在のワークロードに対するメモリ制限を含むさまざまな要因が考えられます。 ほとんどの場合、トランザクションが失敗しても、このエラーは発生しません。 全体的に、原因は次の 3 つに分けられます。

外部または OS のメモリ負荷

外部負荷とは、プロセス外のコンポーネントからのメモリ使用率が高いことを指します。これにより、SQL Server に必要なメモリが不足します。 システム上の他のアプリケーションでメモリが消費されており、それらが低いメモリの可用性に関係していないかどうかを確認する必要があります。 SQL Server は、メモリ使用量を減らすことによって OS メモリ負荷に対応するように設計されている数少ないアプリケーションの 1 つです。 つまり、一部のアプリケーションまたはドライバーでメモリを要する場合、OS ではすべてのアプリケーションにメモリを解放するように指示し、SQL Server ではメモリの使用量を減らすことで対応します。 ごく少数の他のアプリケーションはその通知をリッスンするように設計されていないため、対応しません。 そのため、SQL でメモリ使用量を減らし始めると、そのメモリ プールが減少し、メモリが必要なコンポーネントでそれを得られない場合があります。 701 とその他のメモリ関連のエラーが発生し始めます。 詳細については、「SQL Server メモリ アーキテクチャ」を参照してください

内部メモリ負荷 (SQL Server が原因ではない)

内部メモリ負荷とは、SQL Server プロセス内の要因が原因の低いメモリの可用性を指します。 SQL Server エンジンの "外部" にある SQL Server プロセス内で実行される可能性があるコンポーネントがあります。 たとえば、リンク サーバー、SQLCLR コンポーネント、拡張プロシージャ (XP)、OLE オートメーション (sp_OA*) などの DLL があります。 また、監視目的でプロセス内に Dll を挿入するウイルス対策やその他のセキュリティ プログラムなどがあります。 これらのコンポーネントのいずれかに問題があるか、設計が不適切な場合、メモリの消費量が多くなる可能性があります。 たとえば、外部ソースから SQL Server メモリへの 2,000 万行のデータのキャッシュを行うリンク サーバーがあるとします。 SQL Server に関しては、メモリ クラークでメモリ使用量が多いことは報告されませんが、SQL Server プロセス内で消費されるメモリは多くなります。 たとえば、リンク サーバー DLL からのこのメモリの増加により、SQL Server によってメモリ使用量の削減が開始され (上記を参照)、SQL Server 内部のコンポーネントでメモリ不足の状態となり、701 のようなエラーが発生します。

内部メモリ負荷 (SQL Server コンポーネントが原因)

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

ユーザー アクション

エラー 701 が時々または短い間表示される場合は、自動的に解決された短期間のメモリの問題が発生している可能性があります。 そのような場合は、措置を講じる必要がある可能性があります。 しかし、エラーが複数回、複数の接続で発生し、数秒またはそれ以上続く場合は、次の手順に従ってさらにトラブルシューティングを行ってください。

メモリ エラーのトラブルシューティングに役立つ一般的な手順の概要を以下の一覧に示します。

診断ツールと取り込み

トラブルシューティング データを収集できる診断ツールには、パフォーマンス モニターsys.dm_os_memory_clerks 、および DBCC MEMORYSTATUS があります。

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

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

影響を受けた SQL Server に対するこのクエリの定期的な出力を収集します

SELECT pages_kb, type, name, virtual_memory_committed_kb, awe_allocated_kb
FROM sys.dm_os_memory_clerks
ORDER BY pages_kb DESC

Pssdiag または SQL LogScout

このようなデータ ポイントを取り込むための自動化された別の方法は、PSSDIAGSQL LogScout などのツールを使用することです。

  • Pssdiag を使用する場合は、Perfmon コレクターと Custom Diagnostics\SQL Memory Error コレクターを取り込むように構成します
  • SQL LogScout を使用する場合は、Memory シナリオを取り込むように構成します

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

外部負荷: 診断と解決策

  • SQL Server プロセス外のシステムでメモリ不足状態を診断するには、パフォーマンス モニター カウンターを収集します。 これらのカウンターを参照し、SQL Server 以外のアプリケーションまたはサービスにより、このサーバーでメモリが消費されているかどうかを調査します。

    • Memory:Available MB
    • 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)) }
    }
    }
    
  • システム イベント ログを確認し、メモリ関連のエラー (たとえば、仮想メモリ不足) を探します。

  • アプリケーション イベント ログで、アプリケーション関連のメモリの問題を確認します。

    次に示すのは、System と Applicaiton イベント ログにキーワード "memory" のクエリを実行するサンプル PowerShell スクリプトです。 検索に "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 でLocked Pages in Memory (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 など) からのものである可能性があります。 たとえば、Private bytes が 300 GB で、Total Server Memory が 250 GB の場合は、プロセス内のメモリ全体の約 50 GB が SQL Server エンジン外からのものです。

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

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

    tasklist /M /FI "IMAGENAME eq sqlservr.exe"
    
  • また、このクエリを使用して読み込まれたモジュール (Dll) を調べ、そこにあるはずのないものがないかどうかを確認します

    SELECT * FROM sys.dm_os_loaded_modules
    
  • リンク サーバー モジュールが大量メモリの消費の原因であると思われる場合は、 [InProcess 許可] オプションを無効にすることで、プロセス外で実行されるように構成できます。 詳細については、「リンク サーバーを作成する」を参照してください。 一部のリンク サーバー OLEDB プロバイダーがプロセス外で実行できない可能性があります。詳細については、製品の製造元にお問い合わせください。

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

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 を削除する) か、クエリ ヒントを適用します。
    • 多数のアドホック クエリ プランがキャッシュされている場合、CACHESTORE_SQLCPメモリ クラークは大量のメモリを使用します。 クエリ プランを再利用できないパラメーター化されていないクエリを特定し、ストアド プロシージャに変換するか、sp_executesqlを使用するか、FORCED パラメーター化を使用してパラメーター化します。
    • オブジェクト プラン キャッシュ ストア CACHESTORE_OBJCP で多くのメモリが消費されている場合は、多くのメモリを使用しているストアド プロシージャ、関数、またはトリガーを特定し、場合によってはアプリケーションを再設計します。 一般にこれは、大量のデータベースまたはスキーマがあり、それぞれに数百のプロシージャが含まれることが原因で発生する可能性があります。
    • OBJECTSTORE_LOCK_MANAGER メモリ クラークによって大きなメモリ割り当てが示されている場合は、多くのロックを適用するクエリを特定し、インデックスを使用して最適化します。 特定の分離レベルで長期間ロックが解放されなくなる原因となるトランザクションを短縮するか、ロックのエスカレーションが無効になっているかどうかを確認します。

メモリが使用できるようになる可能性がある迅速な解放

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

  • 次の SQL Server メモリ構成パラメーターを確認し、可能であれば max server memory を増やすことを検討します。

    • max server memory

    • min server memory

      通常とは異なる設定がないか確認します。 必要に応じて、これらを修正します。 高くなったメモリ要件を把握しておきます。 既定の設定については、「サーバー メモリの構成オプション」に記載されています。

  • 特に Locked Pages in Memory で max server memory を構成していない場合は、OS に対して一部のメモリを許可するように特定の値に設定することを検討します。 Locked Pages in Memory サーバー構成オプションを参照してください。

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

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

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

    • DBCC FREESYSTEMCACHE

    • DBCC FREESESSIONCACHE

    • DBCC FREEPROCCACHE

  • Resource Governor を使用している場合は、リソース プールまたはワークロード グループの設定を調べ、メモリの制限が厳しすぎないかどうかを確認します。

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