當 SQL Server 突然出現 CPU 瓶頸時,往往源於查詢未優化、資料庫設定錯誤、設計缺陷或硬體資源不足。在決定增加 CPU 數量或升級更快的處理器前,應優先檢查消耗最多 CPU 資源的操作是否可優化。
效能計數器 Processor: % Processor Time 若持續超過 80%,即可視為 CPU 瓶頸。此外,透過 sys.dm_os_schedulers 檢視 runnable_task_count 是否為非零值,非零代表任務被迫等待時間片,數值越高瓶頸越嚴重。
SELECT scheduler_id, current_task_count, runnable_task_count FROM sys.dm_os_schedulers WHERE scheduler_id < 255;
以下查詢彙總相同查詢控制代碼的所有陳述式 CPU 耗用,列出前 50 筆最耗資源的批次或程序:
SELECT TOP 50
SUM(qs.total_worker_time) AS total_cpu_time,
SUM(qs.execution_count) AS total_execution_count,
COUNT(*) AS number_of_statements,
qs.plan_handle
FROM sys.dm_exec_query_stats qs
GROUP BY qs.plan_handle
ORDER BY SUM(qs.total_worker_time) DESC;
批次或 RPC 提交前,系統會驗證查詢計畫的有效性。驗證失敗會觸發重編譯,產生新計畫。重編譯屬 CPU 敏感操作,過度發生會導致效能下降。
SQL Server 2000 重編譯整個預存程序;SQL Server 2005 引入陳述式層級重編譯,僅重編譯觸發語句,減少 CPU 頻寬與編譯鎖爭用。
WITH RECOMPILE 建立的預存程序監控 SQL Statistics 物件的三個關鍵計數器:
Batch Requests/secSQL Compilations/secSQL Recompilations/sec理想狀態下,Recompilations/sec 與 Batch Requests/sec 比率極低(即席查詢除外)。
使用事件類別:
SP:Recompile(事件類別 37)CursorRecompile(75)SQL:StmtRecompile(166)EventSubClass 欄位揭示重編譯原因。查詢追蹤檔:
SELECT spid, starttime, textdata, eventsubclass, objectid, databaseid, sqlhandle
FROM fn_trace_gettable('filepath.trc', 1)
WHERE EventClass IN (37, 75, 166);
編譯/重編譯時觸發,包含查詢計畫與物件 ID,協助找出頻繁重編譯的陳述式。
sys.dm_exec_query_optimizer_info 顯示優化耗用時間(ElASPsed time 接近 CPU 時間)。
sys.dm_exec_query_stats 中的 plan_generation_num 表示編譯次數。查詢前 25 筆重編譯最多的程序:
SELECT TOP 25
sql_text.text, sql_handle, plan_generation_num,
execution_count, dbid, objectid
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sql_text
WHERE plan_generation_num > 1
ORDER BY plan_generation_num DESC;
KEEP PLAN 提示將暫存表臨界值提升至永久表等級。KEEPFIXED PLAN 提示,僅在正確性相關變更(結構異動、sp_recompile)時重編譯。dbo.table1)避免重編譯與模稜兩可。IF)中混用 DML/DDL。WITH RECOMPILE:SQL Server 2005 改用陳述式層級 OPTION (RECOMPILE),避免整個程序強制重編譯。負載測試期間收集效能計數器與 Profiler 重編譯事件。測試結束後分析計數器確認是否過度編譯/重編譯,再針對追蹤與 DMV 結果找出熱點程序或陳述式,依原因提出解決方案。