SQL Server 2019中窗口函数默认不走批处理模式;其是否启用批处理取决于上游算子(如列存储扫描)是否满足苛刻条件:必须基于列存储索引、兼容级别≥150,且无降级操作。

SQL Server 2019中窗口函数是否走批处理模式?
默认不走。窗口函数本身不触发批处理模式执行,除非它所依赖的上游算子(如扫描、哈希聚合)在满足条件时启用了批处理模式——而这个前提非常苛刻:必须运行在列存储索引(Columnstore Index)上,且查询兼容级别 ≥ 150,且未被强制降级为行模式(例如因 OPTION (USE HINT('DISALLOW_BATCH_MODE')) 或存在不兼容操作)。
哪些窗口函数能受益于批处理模式?
只有部分聚合类窗口函数在列存储场景下可能间接获得批处理加速,例如:SUM()、AVG()、COUNT()、MIN()、MAX();但 ROW_NUMBER()、RANK()、LAG() 等排名/偏移类函数仍强制走行模式,无论底层是否为列存储。
- 原因在于:批处理模式依赖向量化执行,而排序依赖和行序敏感操作(如“当前行前一行”)无法向量化实现
- 即使你在列存储表上写
ROW_NUMBER() OVER (ORDER BY id),执行计划里依然显示Window Spool或Sort运算符,且是行模式 -
AVG(value) OVER (ORDER BY ts ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)这类带ROWS框架的移动聚合,在列存储 + 兼容级别150+ 下,Compute Scalar前的扫描可能批处理,但窗口计算本身仍是行模式
为什么加了 PARTITION BY 反而更慢?
列存储上的窗口聚合若含 PARTITION BY,SQL Server 往往放弃批处理路径,回退到行模式 Window Aggregate 运算符——尤其当分区键基数高或分布不均时。这不是 bug,是优化器权衡后的保守选择。
- 典型现象:执行计划里出现
Window Aggregate(而非Batch Hash Aggregate),且Actual Execution Mode显示Row - 临时缓解:用
GROUP BY+JOIN替代分组窗口,例如先SELECT key, SUM(val) AS grp_sum FROM t GROUP BY key再关联原表 - 硬性限制:SQL Server 2019 不支持对
PARTITION BY窗口函数启用批处理模式,官方文档未将其列为批处理支持场景
真正可控的优化点在哪?
别盯着窗口函数本身调优,要控制它的输入质量和执行环境:
- 确保基表有聚集列存储索引(
CREATE CLUSTERED COLUMNSTORE INDEX),普通堆或行存储 B-tree 索引完全不触发批处理 - 检查数据库兼容级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME(),必须 ≥ 150 - 避免在窗口表达式中混用不兼容操作,例如
CAST非标准类型、UDF、GETDATE()等会导致整个计划降级为行模式 - 用
SET STATISTICS XML ON查看实际执行模式,重点关注ExecutionMode属性值,而不是仅看有没有Batch字样
最常被忽略的一点:即使你写了完美的 SUM() OVER (PARTITION BY x ORDER BY y),只要底层没列存储,或者兼容级别是140,就永远不可能进批处理模式——窗口函数在这里只是“乘客”,不是“司机”。

















