DENSE_RANK不生成不连续排名,因其设计目标是避免跳跃:相同值共享名次,后续名次紧接(如1,1,2,3,3,4);不连续排名应使用RANK或ROW_NUMBER。

为什么 DENSE_RANK 不生成“不连续排名”
DENSE_RANK 的设计目标就是**避免跳跃**:相同值共享一个名次,后续名次紧接(比如 1,1,2,3,3,4)。它天生不支持“不连续排名”——那其实是 RANK 或 ROW_NUMBER 的行为。如果你看到“DENSE_RANK 实现不连续排名”的说法,基本是混淆了需求或误读了结果。
想要不连续序号?用 ROW_NUMBER 而不是 DENSE_RANK
真正生成严格递增、不跳过、无视重复值的序号,该用 ROW_NUMBER()。它的行为就是按排序顺序硬编 1/2/3/…,哪怕多行数据完全一样。
常见错误现象:
– 用 DENSE_RANK() OVER (ORDER BY score DESC) 给分数排名,发现同分学生序号相同,但业务要求每人一个唯一编号(如导出名单序号)
– 误以为加 PARTITION BY 能解决不连续问题,其实只是重置计数,不改变函数本质
实操建议:
- 要唯一、连续、无跳跃的序号 → 无条件选
ROW_NUMBER() - 要体现“并列名次且后续不跳号” → 用
DENSE_RANK() - 要体现“并列名次但后续跳号”(如 95 分两人并列第 1,90 分就直接第 3)→ 用
RANK()
示例(按时间升序编号):
SELECT name, created_at, ROW_NUMBER() OVER (ORDER BY created_at) AS seq_no FROM users;
DENSE_RANK 和 ROW_NUMBER 在 ORDER BY 相同时的区别
当 ORDER BY 列存在重复值,二者差异立刻暴露。这是最容易踩坑的地方——没意识到排序键的粒度不够,导致 ROW_NUMBER 的“确定性”失效。
关键点:
-
ROW_NUMBER()要保证结果稳定,ORDER BY必须能唯一确定每行(比如加上主键:ORDER BY score DESC, id) -
DENSE_RANK()对重复值天然敏感,不需要补唯一键,但它也不需要——它本意就是合并相同排名 - 如果只写
ORDER BY score,ROW_NUMBER()每次执行可能返回不同序号(因无稳定排序依据),而DENSE_RANK()结果恒定
性能提示:两者开销接近,但若为 ROW_NUMBER 补了多余字段(如 ORDER BY score, created_at, id),可能影响索引利用效率。
业务上真需要“不连续排名”,但又想保留 DENSE_RANK 逻辑?
极少数场景下,你既要分组内并列排名(DENSE_RANK),又要给每行一个全局不重复序号(类似流水号)。这不是一个函数能解决的事,得组合。
做法是两层包装:
- 外层用
ROW_NUMBER() OVER (ORDER BY ...)生成唯一序号 - 内层用
DENSE_RANK() OVER (PARTITION BY group_col ORDER BY value_col)算并列排名 - 注意:两个
OVER子句的排序逻辑需对齐,否则序号和排名会错位
容易被忽略的是:这种组合在大数据量下可能触发两次排序,若未建合适索引,性能下降明显。别只盯着函数写法,先看 EXPLAIN 输出里有没有 Sort 节点重复出现。

















