コンパイルするためにメモリを争っている大量のクエリプランがたくさんある場合、この症状が見られると思います(これはクエリ自体の実行とはほとんど関係がありません)。これに当たるには、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つの条件に該当する場合です。
- 指標は通常の値と大幅に異なります。そして、
- 実際に(CPUスパイクのように)パフォーマンスの問題が発生しています。ただし、実際に何かを妨害している場合のみです。CPUのスパイクを確認する以外に、他の症状が発生していますか?つまり、スパイクは症状ですか、それともスパイクは他の症状を引き起こしていますか?システムのユーザーは気づくでしょうか?多くの人々は常にそれが最高だからと言って、最高の待機消費者を追いかけます。何かは常に最も高い待機コンシューマーになるでしょう-それが通常のアクティビティとは十分に異なっており、問題やいくつかの重大な変化を示していることを知っている必要があります。
Optimize for ad hoc workloads
そこにあるワークロードの99%に最適な設定ですが、コンパイルコストの削減にはあまり役立ちません。これは、使い捨てプランが2回実行されるまでプラン全体を保存しないようにすることで、プランキャッシュの肥大化を減らすことを目的としています。 。プランキャッシュにスタブのみを保存する場合でも、クエリを実行するには完全なプランをコンパイルする必要があります。おそらく、@ Kahnが推奨するのは、データベースレベルのパラメーター化をforcedに設定することでした。これにより、より良いプランの再利用が提供される可能性があります(ただし、これらの高コストクエリすべての一意性によって異なります)。
このホワイトペーパーには、プランのキャッシュとコンパイルに関する優れた情報も含まれています。
Optimize for ad hoc workloads
セットは用意されていますが、おっしゃったように、この特定の問題にはあまり関係がありません。多くのユニークなクエリを生成するコードがあり、一部はORMツールから、一部は手動でコーディングされています。私の知る限り、CPUスパイクはユーザーが気付くほど長くは発生していません。データベースを強制パラメーター化に設定すると、私にとって危険に思えます。