本系列第三篇,深入剖析 sys.dm_os_waiting_tasks 在並行查詢中揭示的任務調度內幕。透過雙表鎖定實驗,驗證並行掃描順序;詳細解釋 Scheduler、Worker、Task、Yielding 四大核心概念與關係圖;並提供持續捕捉等待鏈的監控腳本。
-- Session 1:鎖定兩張表 BEGIN TRAN; UPDATE t1 SET b = GETDATE(); UPDATE t2 SET b = GETDATE(); -- 不提交,保持鎖定 -- Session 2:並行聯結查詢 SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.a OPTION (QUERYTRACEON 8649);
查詢 sys.dm_os_waiting_tasks 發現 21 條等待記錄,其中 4 條為 LCK_M_S (共享鎖等待),資源描述指向 t2 的 Hobt ID,證實執行計劃先掃描 t2,而非同時掃描兩表。



CXPACKET 等待。sp_configure 'affinity mask' 綁定物理 CPU。max worker threads (預設依 CPU 核心數自動配置:4 核 512、8 核 576、16 核 704、32 核 960,64 位元環境)。Worker 主動歸還 Scheduler 的關鍵時機:
此機制避免單一 Task 長期佔用 CPU,降低 Context Switch 開銷。


CXPACKET 等待 = 消費者等待生產者資料 (Exchange Port)。LCK_M_S = 掃描運算子等待鎖釋放。

-- 建立暫存表
CREATE TABLE #waiting_log (
grp INT, waiting_task_address VARBINARY(8), session_id SMALLINT,
exec_context_id INT, wait_duration_ms INT, wait_type NVARCHAR(60),
resource_address VARBINARY(8), blocking_task_address VARBINARY(8),
blocking_session_id SMALLINT, blocking_exec_context_id INT
);
DECLARE @grp INT = 0;
WHILE 1=1
BEGIN
INSERT INTO #waiting_log
SELECT @grp, * FROM sys.dm_os_waiting_tasks WHERE session_id > 50;
SET @grp += 1;
WAITFOR DELAY '00:00:00.100'; -- 100ms 採樣
END
-- 分析 (另開視窗執行並行查詢後)
SELECT
grp, wait_type, COUNT(*) AS cnt,
STRING_AGG(CONCAT(session_id,':',exec_context_id), ',') AS participants
FROM #waiting_log
GROUP BY grp, wait_type
ORDER BY grp, cnt DESC;
推測原因:Exchange 運算子僅支援單一生產者流,Union All 為多輸入單一輸出,需序列化拉取各分支資料。期待大神補充官方文件或原始碼層面的解釋。
本系列三篇總結:sys.dm_os_waiting_tasks 能見度遠超 sys.dm_exec_requests,能精準定位並行查詢中每個 Worker 的真實等待類型與阻塞鏈,是 SQL Server 效能調優的「核磁共振」。