RANK() 并列同名且跳过后续名次,如[95,90,90,85]得[1,2,2,4];DENSE_RANK() 并列同名但名次连续,得[1,2,2,3];ROW_NUMBER() 忽略并列纯按顺序编号。

RANK() 会跳过后续名次,遇到并列就“留空”
当多行数据排序值相同时,RANK() 给它们分配相同排名,但下一个不同值的排名会跳过中间数字。比如分数为 [95, 90, 90, 85] 降序排,结果是 [1, 2, 2, 4] —— 第二个 90 和第一个并列第 2,但 85 不是第 3,而是第 4。
这种行为在业务上适合强调“名次间隔”,例如:某次考试只设 1 个一等奖、2 个二等奖,但实际有 3 人并列第二高分,那第三高分的人就自动掉到第四名,不占“三等奖名额”。
-
ORDER BY必须明确,否则RANK()行为不可控(Hive 不保证无序时的行顺序) - 如果漏写
PARTITION BY,整个结果集会被当作一个分区,可能造成全局误排名 - 注意字段类型:字符串型数字(如
'095')按字典序排,会导致'100' ,应先转成数值再排序
DENSE_RANK() 连续分配,相同值之后紧接下一个整数
DENSE_RANK() 遇到重复值也给相同排名,但后续名次不跳过。同样 [95, 90, 90, 85] 降序排,结果是 [1, 2, 2, 3]。它更贴近“梯队感”——前两名是一梯队,第三名是下一梯队,不管前面有没有并列。
典型适用场景是分档位、划等级,比如用户按消费额分“S/A/B/C”四档,你希望消费额相同的用户进同一档,且档位编号连续不中断。
- 和
RANK()一样,ORDER BY缺失会导致结果非确定性,但 Hive 通常报 warning 而非 error - 在
OVER()子句中,PARTITION BY和ORDER BY的组合顺序不影响逻辑,但建议固定写成PARTITION BY ... ORDER BY ...避免阅读歧义 - 如果排序字段含
NULL,默认按NULLS LAST处理(Hive 3.1+),若需NULL排最前,显式加NULLS FIRST
ROW_NUMBER() 不处理并列,纯按物理顺序编号
ROW_NUMBER() 完全不关心值是否重复,只按 ORDER BY 确定的逻辑顺序严格递增编号:哪怕所有值都一样,也会得到 1, 2, 3, 4...。它本质是“带顺序保证的行号”,不是“语义排名”。
这在分页或取 Top-N 时很关键:比如要取每个学科分数最高的 3 个学生,用 ROW_NUMBER() OVER(PARTITION BY subject ORDER BY score DESC) 可确保每科恰好 3 条,哪怕多人同分也不会漏或多。
- 一旦
ORDER BY字段存在大量重复值,ROW_NUMBER()的结果依赖底层 shuffle 顺序,跨集群或多次执行可能不一致 - 若需稳定结果,必须在
ORDER BY中加入唯一字段兜底,例如ORDER BY score DESC, student_id ASC - 不要用
ROW_NUMBER()去实现“并列第一”的业务需求,它天然破坏并列语义
三者性能差异小,但语义选错会导致结果错误
在 Hive 中,RANK()、DENSE_RANK()、ROW_NUMBER() 底层都走相同的窗口计算框架,执行计划和资源消耗几乎无差别。真正影响结果正确性的,是函数语义与业务逻辑的匹配度。
最容易被忽略的是:很多人写完 SQL 发现排名“看起来对”,但上线后因数据分布变化(比如新增并列值)导致下游统计偏差。例如用 RANK() 计算“前 10 名”,结果某次并列第 9 名有 5 人,RANK() 把第 10 名挤到了第 14 名,实际返回了 13 行——而业务方只取 limit 10,直接丢掉 3 个本该入围的人。
所以别只看样例数据跑通,务必用含重复值、边界值(最大/最小/空值)的真实子集验证输出序列。

















