SQL Server 2019中GROUP BY变快的关键是批模式执行(Batch Mode on Rowstore),需满足大中间结果集(>10万行)、合适索引且无阻断运算符(如函数包裹、大字段)才能触发,否则仍走低效行模式。

GROUP BY 为什么在 SQL Server 2019 里变快了
不是所有 GROUP BY 都自动变快,关键在于你是否触发了 SQL Server 2019 新增的批模式执行(Batch Mode on Rowstore)——它能让原本走行模式的 GROUP BY 查询,在不改表结构、不加列存索引的前提下,直接启用向量化聚合,大幅降低 CPU 和内存开销。但这个优化不会自动生效,需要满足几个硬性条件:查询必须涉及足够大的中间结果集(通常 > 10 万行),且聚合字段有合适索引支撑;同时不能存在阻断批模式的运算符(比如 CONVERT、ISNULL 套在分组列上)。
如何确认你的 GROUP BY 正在用批模式
执行带 SET STATISTICS XML ON 的查询后,看执行计划里是否有 Aggregate 运算符的 EstimatedExecutionMode 或 ActualExecutionMode 显示为 Batch。如果仍是 Row,说明没触发。常见拦路虎包括:
-
GROUP BY DATEPART(year, create_time)—— 函数包裹让优化器放弃批模式 - SELECT 中包含
TEXT、NVARCHAR(MAX)等大字段,强制降级为行模式 - WHERE 条件用了
OR且未加括号,导致谓词无法有效下推 - 连接顺序混乱,使聚合前的数据流无法对齐批处理粒度
不依赖批模式时,最有效的三招
即使批模式未启用,以下操作仍能立竿见影:
- 在
GROUP BY列上建非聚集索引,且把 SELECT 中所有非聚合列都包含进去(即覆盖索引)。例如:CREATE INDEX IX_dept_salary ON Employees(dept) INCLUDE (salary),这样SELECT dept, AVG(salary) FROM Employees GROUP BY dept就不用回表 - 把
HAVING条件尽量挪到WHERE。比如统计“平均工资超 1 万的部门”,别写HAVING AVG(salary) > 10000,而是先WHERE salary > 8000缩小输入集再分组 - 避免
GROUP BY多列时顺序错乱。高选择性列(如order_id)放前面反而拖慢,应按值分布广度排序:先region(几十个值),再product_category(几百个),最后status(几个)
别碰 MAXDOP 提示,除非你真懂并行瓶颈
OPTION (MAXDOP 4) 看起来可控,但实际容易适得其反。SQL Server 2019 的查询优化器对并行阈值判断更准,手动设 MAXDOP 可能打断批模式调度,或让小查询强行并行反而增加线程调度开销。真正该调的是服务器级配置:sp_configure 'cost threshold for parallelism',默认 5 不适合 OLAP 类 GROUP BY,可试调至 25–50,再配合 SET STATISTICS IO 观察逻辑读变化。
批模式是隐藏开关,不是银弹;索引和过滤才是每天都能见效的抓手。最容易被忽略的,其实是 WHERE 里那个本可以提前筛掉 90% 行的日期范围条件——它比调任何参数都管用。


















