window子句需兼容级别160,升级后不可降级,旧隐式转换可能报错;重复窗口定义应改用window提升编译效率;order by含变量时需启用查询存储以触发参数敏感计划;window作用域限于当前select,不支持跨cte、嵌套或动态表达式。

WINDOW 子句必须配兼容性级别 160
不升级就用不了 WINDOW 子句,SQL Server 2022 解析器在低于 160 的兼容级别下根本认不出这个关键字,直接报错 Incorrect syntax near 'WINDOW'。
升级命令是硬性操作:
ALTER DATABASE YourDB SET COMPATIBILITY_LEVEL = 160;
注意三点:
- 升级后无法降级回 150 或更低(除非重建数据库)
- 旧版隐式类型转换规则可能变化,比如
ISNULL('a', 1)在 160 下会报错,而 140 下能隐式转成字符串 - 建议先在测试库运行
SELECT compatibility_level FROM sys.databases WHERE name = 'YourDB'确认当前值
重复窗口定义时优先用 WINDOW 而不是复制 OVER
当多个窗口函数共享同一分区和排序逻辑(比如都按 PARTITION BY dept_id ORDER BY salary DESC),手写多个 OVER (PARTITION BY ... ORDER BY ...) 会让 SQL Server 每次都重新解析表达式,影响计划缓存复用率和编译时间。
改用 WINDOW 后,解析只做一次,执行计划里也只生成一份窗口元数据。实测在含 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 这类复杂帧定义的场景下,编译耗时可降 30% 以上。
对比写法:
-- 旧写法:重复定义,每次解析 SELECT dept_id, salary, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn, AVG(salary) OVER (PARTITION BY dept_id ORDER BY salary DESC) AS avg_sal FROM employee;
-- 新写法:一次定义,多处引用 SELECT dept_id, salary, ROW_NUMBER() OVER w AS rn, AVG(salary) OVER w AS avg_sal FROM employee WINDOW w AS (PARTITION BY dept_id ORDER BY salary DESC);
ORDER BY 字段带参数时留意参数敏感计划(PSP)
如果窗口函数的 ORDER BY 依赖变量(如 ORDER BY @sort_col),且不同参数值导致数据分布差异极大(例如按地区排序 vs 按金额排序),SQL Server 2022 的参数敏感计划(PSP)可能为不同参数生成独立执行计划。
这不是自动开启的,需满足两个前提:
- 数据库兼容级别 ≥ 160
- 查询存储(Query Store)已启用,且未被禁用
若发现某参数下窗口排序严重溢出 tempdb,可手动触发重编译:EXEC sp_recompile 'YourProcName',让 PSP 有机会捕获基数偏差并生成新计划。
别忽略 WINDOW 子句的限制范围
WINDOW 子句只作用于当前 SELECT 语句,不能跨 CTE、子查询或视图复用。比如在 CTE 中定义的窗口名,在外部 SELECT 中不可见。
也不能嵌套引用:定义 w1 AS (...) 后,w2 AS (w1) 是非法的,reference_window_name 只支持同级定义间的平级引用,不支持继承。
更关键的是:它不接受动态表达式——PARTITION BY 和 ORDER BY 后的字段必须是确定列名或常量,不能是 CASE WHEN 或函数调用结果(除非该函数是确定性的且被优化器提前折叠)。











