次の方法で共有


MSSQLSERVER_701

適用対象: SQL サーバー

詳細

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

Note

この記事では、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 にメモリを割り当てる何百ものコンポーネントが sys.dm_os_memory_clerks経由で追跡されています。 これをさらに解決できるように、最大メモリ割り当てを行うメモリ クラークを特定する必要があります。 たとえば、OBJECTSTORE_LOCK_MANAGER メモリ クラークが大きなメモリ割り当てを示していることがわかった場合は、ロック マネージャーで非常に多くのメモリが消費されている理由をさらに理解する必要があります。 大量のロックを取得してインデックスを使用して最適化するクエリや、ロックを長期間保持するトランザクションを短縮するクエリ、またはロックエスカレーションが無効になっているかどうかを確認するクエリがある場合があります。 各メモリ クラークまたはコンポーネントには、メモリにアクセスして使用するための独自の方法があります。 詳細については、 sys.dm_os_memory_clerks とその説明を参照してください。

ユーザー アクション

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

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

    次に示すのは、キーワード "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 が Lock 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 がメモリ ロック ページ (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 バイト カウンターが 5 ~ 4 GB で、SQL Server がメモリ内の Lock ページ (AWE) を使用している場合、プライベート バイトの大部分は SQL Server エンジンの外部から取得できます。 これは近似法です。

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

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

    SELECT * FROM sys.dm_os_loaded_modules
    
  • リンク サーバー モジュールが大量メモリの消費の原因であると思われる場合は、[InProcess 許可] オプションを無効にすることで、プロセス外で実行されるように構成できます。 詳細については、「リンク サーバーの作成 (SQL Server データベース エンジン)」を参照してください。 すべてのリンク サーバー 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

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

  • max サーバー メモリを構成していない場合は特にメモリ内の Lock ページを使用、OS のメモリを許可するように特定の値に設定することを検討してください。 メモリ内のページのロックサーバー構成オプションに関するページを参照してください。

  • クエリ ワークロードを確認します。同時セッションの数。現在クエリを実行しており、一時的に停止したり、別の SQL Server に移動したりできる重要度の低いアプリケーションがあるかどうかを確認します。

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

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

    • DBCC FREESYSTEMCACHE

    • DBCC FREESESSIONCACHE

    • DBCC FREEPROCCACHE

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

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