执行计划中“Parallelism”不等于真并行,需用SET STATISTICS XML ON查<RelOp LogicalOp="Parallelism">节点是否为Gather/Repartition Streams,并结合cxpacket等待、JOIN算法类型及数据倾斜情况综合判断。

看执行计划里有没有真正的并行操作符
执行计划写着“Parallelism”不等于真在并行——很多情况下只是个空壳。必须打开实际执行计划(SET STATISTICS XML ON),找<RelOp LogicalOp="Parallelism">节点,确认它是否出现在JOIN算子的上游或下游,且类型是Gather Streams或Repartition Streams。如果只有Parallelism (Gather Streams)在最外层,而内部全是串行扫描或索引查找,说明并行被降级了,可能因为统计信息不准、存在标量UDF、或MAXDOP被全局压制。
查sys.dm_os_wait_stats里的cxpacket和threadpool
并行开销最直接的体现是等待行为。运行以下语句抓取当前会话或实例级等待:
SELECT wait_type, waiting_tasks_count, wait_time_ms
FROM sys.dm_os_wait_stats
WHERE wait_type IN ('cxpacket', 'threadpool', 'latch_ex', 'pageiolatch_sh');cxpacket高但wait_time_ms占比低(比如<5%总等待),说明线程协作正常;若cxpacket占总等待70%以上,且signal_wait_time_ms远高于wait_time_ms - signal_wait_time_ms,大概率是数据倾斜或内存不足导致部分线程空等。同时出现高threadpool,说明线程创建失败,可能max worker threads设得太低或CPU过载。
用STATISTICS IO和STATISTICS TIME比对串行/并行版本
别只信执行时间,要拆开看资源消耗:
- 加
OPTION (MAXDOP 1)强制串行,记下logical reads和CPU time - 去掉提示跑原查询,再对比两组输出
- 如果并行版
logical reads翻倍、CPU time涨3倍但elapsed time只降20%,说明并行带来额外调度和同步开销,得不偿失
特别注意:当JOIN键存在严重倾斜(比如90%的customer_id是NULL或0),并行线程分配的数据量极不均衡,elapsed time可能比串行还长——这时WHERE customer_id IS NOT NULL提前过滤比调大MAXDOP更有效。
确认JOIN算法是否真的支持并行化
不是所有JOIN都能并行。SQL Server中只有Hash Match和Merge Join能真正并行,Nested Loops仅外层可并行(内层仍是串行驱动)。检查执行计划中LogicalOp值:
-
Hash Match:支持完整并行,build和probe两边都会出现Repartition Streams -
Merge Join:仅当两边输入都满足Ordered="true"且方向一致时才启用并行;否则退化为串行Merge或悄悄加Sort -
Nested Loops:执行计划里看到Parallelism (Gather Streams)只包在外层循环上,内层仍是单线程逐行查找,容易成为瓶颈
最容易被忽略的一点:Merge Join的并行性高度依赖物理有序性——哪怕有索引,如果ORDER BY方向不一致(如一边ASC、一边DESC),或连接列存在隐式转换(UPPER(name) = UPPER(@name)),优化器就无法认定输入有序,并行Merge直接失效。

















