row_number()必须配合over()使用,否则报错;正确写法为row_number() over (order by column),分组需加partition by,且order by不可省略以确保编号确定性与性能。

ROW_NUMBER() 必须配合 OVER() 使用,否则报错
直接写 SELECT ROW_NUMBER(), name FROM users 会触发错误:「窗口函数必须有 OVER 子句」。SQL 强制要求你明确指定排序依据和分组逻辑,哪怕只是简单按某列排序。
正确写法是:SELECT ROW_NUMBER() OVER (ORDER BY id), name FROM users。这里 OVER (ORDER BY id) 不仅决定序号顺序,也决定了序号是否连续、是否可预测——没 ORDER BY 就没有确定性,不同执行可能出不同结果。
用 PARTITION BY 实现分组内独立编号
当需要按类别重置序号(比如每个部门内员工从 1 开始编号),就得加 PARTITION BY。它不是“分组聚合”,而是“逻辑切片”:
• ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) 表示:先按 dept_id 切成若干块,每块内部再按 salary 降序排,然后从 1 开始编号
• 注意 PARTITION BY 和 GROUP BY 完全无关,不能替代聚合操作;它只影响编号范围,不减少行数
• 如果漏掉 ORDER BY,即使写了 PARTITION BY,仍会报错
ORDER BY 在 OVER 中的排序优先级高于外部 ORDER BY
如果同时写了窗口函数里的 ORDER BY 和查询末尾的 ORDER BY,两者独立生效:
• 窗口函数内的 ORDER BY 只管编号生成逻辑(比如谁该是第 1 名)
• 外层 ORDER BY 控制最终结果集的显示顺序
• 二者顺序不一致时,容易误以为编号“乱了”。例如:ROW_NUMBER() OVER (ORDER BY created_at) 生成序号后,又写 ORDER BY name,那么序号列是按时间生成的,但整行是按姓名排的——序号不会跟着姓名重排
• 实际开发中,建议让两者一致,或至少在注释里标明编号依据
性能敏感场景慎用非索引字段排序
ROW_NUMBER() 的开销主要来自 OVER 中的排序。如果 ORDER BY 字段没索引:
• 大表上会触发文件排序(Using filesort),内存不足时写磁盘,速度骤降
• MySQL 8.0+、PostgreSQL、SQL Server 都无法下推该排序到索引扫描,必须全量排序后再编号
• 解决办法:确认排序字段有单列索引或复合索引前导列;若业务允许,用主键或带索引的时间字段代替业务字段排序
• 特别注意:MySQL 5.7 不支持窗口函数,强行用会报错 FUNCTION xxx.ROW_NUMBER does not exist,得升级或改用变量模拟(但不推荐)











