断続的なRESOURCE_SEMAPHORE_QUERY_COMPILE待機統計


8

運用中のSQL Serverの1つで発生している断続的なCPUスパイクのトラブルシューティングを試みています。28 GBのRAMと4つのCPUコアを備えたSQL Server 2008 R2 Standard Editionを実行しています。これが発生すると、RESOURCE_SEMAPHORE_QUERY_COMPILERの待機が多数あることに気づきます。これは約1〜2分続き、その後停止して、CPU使用率は通常に戻ります。

これを調査した結果、これは通常、再利用できない多数の実行プランをコンパイルしたことが原因であると理解しています。

この動作は、メモリプレッシャーによるプランキャッシュの削除によってもトリガーされますか?もしそうなら、私はこれをどのようにチェックしますか?アプリケーションの修正を展開するまで、サーバーRAMのアップグレードなどの短期的な解決策があるかどうかを確認しようとしています。私が考えることができる他の唯一の短期間のオプションは、最も忙しいデータベースのいくつかを別のサーバーに移動することです。

回答:


6

コンパイルするためにメモリを争っている大量のクエリプランがたくさんある場合、この症状が見られると思います(これはクエリ自体の実行とはほとんど関係がありません)。これに当たるには、ORMや、多くのユニークだが比較的複雑なクエリを生成する何らかのアプリケーションを使用しているのではないかと思います。SQL Serverは、クエリ操作が大きいなどの理由でメモリ不足になっている可能性がありますが、さらに考えれば、システムが必要なメモリよりもはるかに少ないメモリで構成されている可能性が高くなります(すべてのクエリを満たすのに十分なメモリがない場合)コンパイルしようとしているか、SQL Serverからメモリを盗んでいる他のプロセスがボックスにあります)。

以下を使用して、SQL Serverの構成を確認できます。

EXEC sp_configure 'max server memory';    -- max configured in MB

SELECT counter_name, cntr_value
  FROM sys.dm_os_performance_counters
  WHERE counter_name IN
  (
    'Total Server Memory (KB)',    -- max currently granted
    'Target Server Memory (KB)'    -- how much SQL Server wished it had
  );

次のJonathan Kehayiasクエリを少し調整して、最も多くのコンパイルメモリ必要とするキャッシュされたプランを特定できます

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')
SELECT TOP (10) CompileTime_ms, CompileCPU_ms, CompileMemory_KB,
  qs.execution_count,
  qs.total_elapsed_time/1000.0 AS duration_ms,
  qs.total_worker_time/1000.0 as cputime_ms,
  (qs.total_elapsed_time/qs.execution_count)/1000.0 AS avg_duration_ms,
  (qs.total_worker_time/qs.execution_count)/1000.0 AS avg_cputime_ms,
  qs.max_elapsed_time/1000.0 AS max_duration_ms,
  qs.max_worker_time/1000.0 AS max_cputime_ms,
  SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1,
    (CASE qs.statement_end_offset
      WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset
     END - qs.statement_start_offset) / 2 + 1) AS StmtText,
  query_hash, query_plan_hash
FROM
(
  SELECT 
    c.value('xs:hexBinary(substring((@QueryHash)[1],3))', 'varbinary(max)') AS QueryHash,
    c.value('xs:hexBinary(substring((@QueryPlanHash)[1],3))', 'varbinary(max)') AS QueryPlanHash,
    c.value('(QueryPlan/@CompileTime)[1]', 'int') AS CompileTime_ms,
    c.value('(QueryPlan/@CompileCPU)[1]', 'int') AS CompileCPU_ms,
    c.value('(QueryPlan/@CompileMemory)[1]', 'int') AS CompileMemory_KB,
    qp.query_plan
FROM sys.dm_exec_cached_plans AS cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp
CROSS APPLY qp.query_plan.nodes('ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS n(c)
) AS tab
JOIN sys.dm_exec_query_stats AS qs ON tab.QueryHash = qs.query_hash
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY CompileMemory_KB DESC
OPTION (RECOMPILE, MAXDOP 1);

プランキャッシュが次のようにどのように使用されているかを確認できます。

SELECT objtype, cacheobjtype,
    AVG(size_in_bytes*1.0)/1024.0/1024.0,
    MAX(size_in_bytes)/1024.0/1024.0,
    SUM(size_in_bytes)/1024.0/1024.0,
    COUNT(*)
FROM sys.dm_exec_cached_plans
GROUP BY GROUPING SETS ((),(objtype, cacheobjtype))
ORDER BY objtype, cacheobjtype;

高いセマフォ待機が発生している場合は、これらのクエリ結果が「通常」のアクティビティと大幅に異なるかどうかを確認してください。

SELECT resource_semaphore_id, -- 0 = regular, 1 = "small query"
  pool_id,
  available_memory_kb,
  total_memory_kb,
  target_memory_kb
FROM sys.dm_exec_query_resource_semaphores;

SELECT StmtText = SUBSTRING(st.[text], (qs.statement_start_offset / 2) + 1,
        (CASE qs.statement_end_offset
          WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset
         END - qs.statement_start_offset) / 2 + 1),
  r.start_time, r.[status], DB_NAME(r.database_id), r.wait_type, 
  r.last_wait_type, r.total_elapsed_time, r.granted_query_memory,
  m.requested_memory_kb, m.granted_memory_kb, m.required_memory_kb,
  m.used_memory_kb
FROM sys.dm_exec_requests AS r
INNER JOIN sys.dm_exec_query_stats AS qs
ON r.plan_handle = qs.plan_handle
INNER JOIN sys.dm_exec_query_memory_grants AS m
ON r.request_id = m.request_id
AND r.plan_handle = m.plan_handle
CROSS APPLY sys.dm_exec_sql_text(r.plan_handle) AS st;

また、メモリがどのように分散されているかを確認することもできます。

DBCC MEMORYSTATUS;

そして、なぜあなたが大量のコンパイル/再コンパイルを見ているのかについての良い情報があります(それはその待機の一因となります):

http://technet.microsoft.com/en-us/library/ee343986(v=sql.100).aspx

http://technet.microsoft.com/en-us/library/cc293620.aspx

次のカウンタを使用して、コンパイル/再コンパイルの数が多いかどうかを確認できます。

SELECT counter_name, cntr_value
  FROM sys.dm_os_performance_counters
  WHERE counter_name IN 
  (
    'SQL Compilations/sec',
    'SQL Re-Compilations/sec'
  );

そして、あなたは立ち退きにつながる内部メモリプレッシャーをチェックすることができます-ここでゼロ以外のカウンターは、何かが良くないことが計画キャッシュで起こっていることを示します:

SELECT * FROM sys.dm_os_memory_cache_clock_hands 
  WHERE [type] IN (N'CACHESTORE_SQLCP', N'CACHESTORE_OBJCP');

これらのメトリックのほとんどには、「ああ、なんとかパニックまたは何かする必要がある!」という魔法はありません。しきい値。実行する必要があるのは、通常のシステムアクティビティ中に測定を行い、これらのしきい値がハードウェア、構成、およびワークロードのどこにあるかを判断することです。あなたはときにパニックに何かを行う2つの条件に該当する場合です。

  1. 指標は通常の値と大幅に異なります。そして、
  2. 実際に(CPUスパイクのように)パフォーマンスの問題が発生しています。ただし、実際に何かを妨害している場合のみです。CPUのスパイクを確認する以外に、他の症状が発生していますか?つまり、スパイクは症状ですか、それともスパイクは他の症状を引き起こしていますか?システムのユーザーは気づくでしょうか?多くの人々は常にそれが最高だからと言って、最高の待機消費者を追いかけます。何かは常に最も高い待機コンシューマーになるでしょう-それが通常のアクティビティとは十分に異なっており、問題やいくつかの重大な変化を示していることを知っている必要があります。

Optimize for ad hoc workloadsそこにあるワークロードの99%に最適な設定ですが、コンパイルコストの削減にはあまり役立ちません。これは、使い捨てプランが2回実行されるまでプラン全体を保存しないようにすることで、プランキャッシュの肥大化を減らすことを目的としています。 。プランキャッシュにスタブのみを保存する場合でも、クエリを実行するには完全なプランをコンパイルする必要があります。おそらく、@ Kahnが推奨するのは、データベースレベルのパラメーター化をforcedに設定することでした。これにより、より良いプランの再利用が提供される可能性があります(ただし、これらの高コストクエリすべての一意性によって異なります)。

このホワイトペーパーには、プランのキャッシュとコンパイルに関する優れた情報も含まれています。


現在、このOptimize for ad hoc workloadsセットは用意されていますが、おっしゃったように、この特定の問題にはあまり関係がありません。多くのユニークなクエリを生成するコードがあり、一部はORMツールから、一部は手動でコーディングされています。私の知る限り、CPUスパイクはユーザーが気付くほど長くは発生していません。データベースを強制パラメーター化に設定すると、私にとって危険に思えます。
DanM 2014

一つの質問-あなたが高いコンパイルをチェックするとき、実際に高い数を構成するものは何ですか?バッチリクエスト数/秒と比較した場合、コンパイル/秒は意味があるだけだと思いました。
DanM 2014

@DanM上で言ったように、私はあなたの環境にとって何が高いのかを知る方法はありません。なぜなら私はあなたの環境にとって何が正常であるかわからないからです。数が1秒あたりのバッチリクエスト数に近いか、それより大きい場合、それはインジケーターである可能性がありますが、やはり異なります。たとえば、バッチが5000個のステートメントで構成されており、そのうちの10個が再コンパイルを必要とする場合(これはステートメントレベルで発生する可能性があるため)、バッチ/秒と比較してcomp / secは10倍になります。問題ありますか?
アーロンバートランド

@DanMまた、インターネット上の誰かがそうするように言ったので、それをテストして有効にするだけではないという暗黙の免責事項を使用して、データベースまたはグローバル設定を変更することをお勧めします。:-)私は変更が役立つかもしれない方法と理由を説明しようとするが、私は常に明白なことを述べることを覚えていない:最初のテストを
アーロンバートランド

私はあなたの要点を理解しています-「高」編集を構成するものは完全に環境に依存しています。
DanM 2014

-1

これらの待機が表示されるのをこれまで見てきた最も典型的な理由は、断片化されたインデックスまたは不十分なインデックス、およびサンプルサイズが不十分であるか時代遅れの統計の結果です。これにより、大量の全テーブルスキャンがすべてのメモリを占有し、RESOURCE_SEMAPHORE_QUERY_COMPILEとしてよく見られる症状を引き起こします。

これを確認する最も簡単な方法は、インデックスシークを実行する必要があるときに、クエリが全テーブルスキャンまたはインデックススキャンを実行するかどうかを確認することです。問題を再現できる問題クエリがある場合、これを診断して修正するのが非常に簡単になります。

これらの問題のあるクエリの影響を受けるテーブルのインデックスを確認します。インデックスの断片化、使用されていない可能性のあるフィルター処理されたインデックス、作成する可能性のあるインデックスの欠落などを確認してください。また、できるだけ早くFULLSCANで統計を更新してください。

覚えておくと良いのは、問題のあるテーブルがこれを必要とする唯一のものではないかもしれないということです。たとえば、10個のテーブルからデータをフェッチするクエリがある場合、実行プランナーはテーブル1のインデックスを使用していないことを時々示すことがありますが、テーブル1のインデックスを確認すると、実際には問題ありません。クエリプランナーは、たとえばテーブル7のインデックスに欠陥がある/不十分な場合に大量のデータが返されるため、高速なオプションになるため、テーブル全体を正しくスキャンして、テーブル1のデータを正しくフェッチするように解決できます。したがって、これらを診断するのは難しい場合があります。

また、たとえば変数値の変更がほんの少しのコードビハインドクエリが多数ある場合は、アドホックワークロードの最適化を有効にすることを検討することをお勧めします。基本的には、プラン全体ではなく、コンパイルされたプランのスタブを保存し、毎回まったく同じプランをまったく取得できない場合にリソースを節約します。


強調することのほとんどは、コンパイル時間が長くなるのではなく、クエリプランが非効率になる原因になります。私見では。
アーロンバートランド

それにもかかわらず、これが何度か発生するのを見たことがあります。明らかに、それがどれほど一般的であるか、またはそれがここに当てはまるかどうかはわかりませんが、上記の方法で修正されました。
カーン、

後編集として、私たちの場合、常に実行されている多数のクエリによって使用された重要なインデックス/統計が影響を受けた後、かなり大きなDBに表示されます。
カーン

1
そうです、コンパイルの待機は、インデックス/統計が変更されたために発生しました。これにより、関連するすべての計画が再コンパイルされました。それらが断片化されていたり、古くなっているためではありません(回答の状態など)。
アーロンバートランド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.