跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何在MySQL 8.0中使用窗口函数实现排名查询_通过RANK和DENSE_RANK

RANK()和DENSE_RANK()均需配合OVER(ORDER BY)使用,区别在于并列时RANK()跳号(如1,1,3)、DENSE_RANK()不跳号(如1,1,2),且二者仅可用于SELECT列表,不可出现在WHERE或GROUP BY中。 MySQL 8.0中RANK()和DENSE_RANK()的基本用法区别 MySQL 8.0开始原生支持窗口函数,
RANK()
和
DENSE_RANK()
都能实现分组内排序编号,但处理并列的方式不同:遇到相同值时,
RANK()
会跳过后续名次(比如 1,1,3),而
DENSE_RANK()
不跳过(1,1,2)。这个差异直接影响业务语义——比如“年级前10名”用
RANK()
可能实际返回12人,“同分同名次且不空号”则必须选
DENSE_RANK()
。 两者语法完全一致,都依赖
OVER()
子句定义排序逻辑:
SELECT name, score, RANK() OVER (ORDER BY score DESC) AS rank_num, DENSE_RANK() OVER (ORDER BY score DESC) AS dense_num FROM students;
按部门分组排名时必须加PARTITION BY 如果要查“每个部门内员工薪资排名”,漏写
PARTITION BY dept
就会变成全表统一排名,这是新手最常踩的坑。窗口函数不会自动按 GROUP BY 分组,它只认
OVER()
里的显式声明。 正确写法示例:
SELECT dept, name, salary, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS dept_rank FROM employees;
PARTITION BY dept
表示按部门切片,各组独立计算排名 ORDER BY 必须存在,否则报错
Window 'w' lacks an ORDER BY clause
若需先按部门、再按入职时间保序,可写
ORDER BY salary DESC, hire_date ASC
ORDER BY 中NULL值影响排名结果 MySQL 8.0默认把
NULL
当作最小值(等价于
NULLS FIRST
),所以
ORDER BY score DESC
会让
NULL
排在最后;但若字段本身含大量
NULL
,且你希望它们排最前或忽略,就得显式控制: MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 让 NULL 排最前:
ORDER BY score DESC NULLS FIRST
让 NULL 排最后(默认行为):
ORDER BY score DESC NULLS LAST
彻底排除 NULL 行:
WHERE score IS NOT NULL
(推荐在 WHERE 阶段过滤,比在窗口里处理更高效) 不声明
NULLS FIRST/LAST
时,不同 MySQL 版本或 SQL 模式下行为可能不一致,线上环境务必显式指定。 性能注意:大表上慎用无索引的ORDER BY字段 窗口函数的
ORDER BY
字段如果没有索引,MySQL 会强制触发临时表 + filesort,数据量稍大(比如百万级)就明显变慢。这不是语法问题,而是执行计划层面的瓶颈。 检查执行计划:
EXPLAIN SELECT ... RANK() OVER (ORDER BY unindexed_col) ...
,关注
Extra
列是否出现
Using temporary; Using filesort
给排序字段建索引:
ALTER TABLE students ADD INDEX idx_score_desc (score DESC);
(MySQL 8.0 支持降序索引) 避免在
ORDER BY
中用函数或表达式,如
ORDER BY ABS(score)
会导致索引失效 真正容易被忽略的是:即使加了索引,如果
PARTITION BY
和
ORDER BY
字段组合无法命中联合索引前缀,照样会回退到临时表。这时候得按分区键+排序键建联合索引。

相关文章