不写 order by 会导致结果不可靠,mysql 8.0+ 直接报错;partition by 选错字段引发数据倾斜;rows/range 混用语义错误;嵌套窗口函数语法禁止。

窗口函数里 ORDER BY 不写会怎样?
不写 ORDER BY,多数数据库(如 postgresql、SQL Server)仍能执行,但结果不可靠——尤其是涉及 ROW_NUMBER()、RANK() 这类依赖顺序的函数。MySQL 8.0+ 会直接报错 Window 'w' lacks an ORDER BY clause。
- 分区后不排序,相当于在无序集合上编号,每次查询可能返回不同行号
- 若业务依赖“最新一条记录”,漏掉
ORDER BY created_at DESC就会拿错数据 - 性能上,加
ORDER BY可能触发排序操作,但比后期用子查询补救更可控
PARTITION BY 字段选错导致数据倾斜
常见错误是拿高基数字段(如 user_id)做分区,却没意识到它会导致大量小窗口,拖慢执行;或用低基数字段(如 status 只有 3 个值),让单个窗口过大,内存溢出。
- 查下字段唯一值数量:
select count(DISTINCT user_id) FROM orders,如果接近总行数,慎用它分区 - 优先选业务语义清晰、粒度适中的字段,比如
date_trunc('month', order_time)比裸order_time更稳 - PostgreSQL 中窗口函数不会自动并行,分区越碎,并行度越低;反之,单个分区超百万行易 OOM
ROWS BETWEEN 和 RANGE BETWEEN 别混用
两者语义完全不同:ROWS 数物理行数,RANGE 按排序值范围取。用错会得到完全偏离预期的累计值。
- 想算“最近 7 天销售额”,必须用
RANGE BETWEEN INTERVAL '6 days' PRECEDING AND CURRENT ROW;用ROWS BETWEEN 6 PRECEDING AND CURRENT ROW会漏掉某天没订单的空档 - 对时间字段用
ROWS,等于假设数据均匀分布,实际几乎从不成立 - MySQL 不支持
INTERVAL在窗口帧中,得先生成连续日期序列再LEFT JOIN补齐
嵌套窗口函数为什么报错 Window function is not allowed in window definition?
这是语法硬限制:你不能在 OVER 子句里再调一次窗口函数,比如 AVG(ROW_NUMBER() OVER (...)) OVER (...)。
- 典型误操作:想先编号再取中位数,结果写成
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ROW_NUMBER() OVER (...))—— 错,ROW_NUMBER()本身不能出现在聚合函数参数里 - 解法只有两层:外层子查询 / CTE 先算好窗口值,再在外层对结果集做聚合
- 别指望用
LAG()包裹LEAD()来“绕过”,语法校验阶段就拦住了
窗口函数不是万能胶,分区键选得毛躁、帧定义想当然、嵌套一层就以为能链式处理——这些地方一松劲,结果就偏得离谱。真正卡住性能或逻辑的,往往就藏在 ORDER BY 缺失、RANGE 误写成 ROWS 这种一眼扫过去觉得“应该没问题”的地方。