本文對Hive中經常使用的三個排序函數row_number()
、dense_rank()
、rank()
的特性進行類比和總結,並經過筆者親自動手寫的一個小實驗,直觀展示這三個函數的特色。sql
函數 | 共同點 | 不一樣點 |
row_number() | 用於特定場景下實現排序需求; 均從1開始排序 |
無重複排名(相同排名的按序排名) |
dense_rank() | 有相同排名,但不會跳過佔用的排名 | |
rank() | 有相同排名,但會跳過佔用的排名 |
set mapreduce.job.queuename=QueueA; use STUDENT_DB; --建立學生分數表 DROP TABLE IF EXISTS STUDENT_DB.SCORE_TABLE1; CREATE TABLE IF NOT EXISTS STUDENT_DB.SCORE_TABLE1 ( ID STRING COMMENT '惟一ID', NAME STRING COMMENT '姓名', SCORE INT COMMENT '分數', CLASS_NUM STRING COMMENT '班級編號' ) COMMENT '學生分數表' PARTITIONED BY (pt_dt STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\27' STORED AS ORCFILE; --向學生分數表插入數據 INSERT OVERWRITE TABLE STUDENT_DB.SCORE_TABLE1 PARTITION(pt_dt='2019-12-12') VALUES ('1', '小明', 89, '1班'), ('2', '小紅', 90, '1班'), ('3', '小軍', 90, '1班'), ('4', '小胖', 91, '1班'), ('5', '小李', 87, '1班'), ('6', '小郭', 99, '1班'); --建立學生分數排序結果表 DROP TABLE IF EXISTS STUDENT_DB.SCORE_RANK_TABLE1; CREATE TABLE IF NOT EXISTS STUDENT_DB.SCORE_RANK_TABLE1 ( ID STRING COMMENT '惟一ID', NAME STRING COMMENT '姓名', SCORE INT COMMENT '分數', CLASS_NUM STRING COMMENT '班級編號', ROW_NUMBERS STRING COMMENT 'ROW_NUMBER排序結果', DENSE_RANKS STRING COMMENT 'DENSE_RANKS排序結果', RANKS STRING COMMENT 'RANKS排序結果' ) COMMENT '學生分數排序結果表' PARTITIONED BY (pt_dt STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\27' STORED AS ORCFILE; INSERT OVERWRITE TABLE STUDENT_DB.SCORE_RANK_TABLE1 PARTITION(pt_dt='2019-12-12') SELECT ID, NAME, SCORE, CLASS_NUM, ROW_NUMBER() OVER(PARTITION BY CLASS_NUM ORDER BY SCORE DESC) AS ROW_NUMBERS, DENSE_RANK() OVER(PARTITION BY CLASS_NUM ORDER BY SCORE DESC) AS DENSE_RANKS, RANK() OVER(PARTITION BY CLASS_NUM ORDER BY SCORE DESC) AS RANKS FROM STUDENT_DB.SCORE_RANK_TABLE1 WHERE pt_dt='2019-12-12'; SELECT ID, NAME, SCORE, CLASS_NUM, ROW_NUMBERS, DENSE_RANKS, RANKS, pt_dt FROM STUDENT_DB.SCORE_RANK_TABLE1 WHERE pt_dt='2019-12-12';
SCORE_RANK_TABLE1函數
ID | NAME | SCORE | CLASS_NUM | ROW_NUMBERS | DENSE_RANKS | RANKS | pt_dtpt_dt |
---|---|---|---|---|---|---|---|
6 | 小郭 | 99 | 1班 | 1 | 1 | 1 | 2019-12-12 |
4 | 小胖 | 91 | 1班 | 2 | 2 | 2 | 2019-12-12 |
3 | 小軍 | 90 | 1班 | 3 | 3 | 3 | 2019-12-12 |
2 | 小紅 | 90 | 1班 | 4 | 3 | 3 | 2019-12-12 |
1 | 小明 | 89 | 1班 | 5 | 4 | 5 | 2019-12-12 |
5 | 小李 | 87 | 1班 | 6 | 5 | 6 | 2019-12-12 |
如上表所示,1班的小軍和小紅分數均爲90,當咱們使用ROW_NUMBERS()
進行排序時,他們的排名不會並列,而是分別有一個排名。性能
當咱們使用DENSE_RANK()
進行排序時,他們的排名會並列,且後續記錄的排名會以當前並列排名爲基礎+1,即不會跳過被佔用的位置。大數據
當咱們使用RANK()
進行排名時,他們的排名會並列,且後續記錄的排名會跳過被佔用的排名數,而不會順延下去。spa
在實際開發過程當中,可根據場景的須要去選擇具體的排序函數。一個較爲常見的場景是根據某個字段partition by
以後在該範圍內order by
進行排序,而後取首條記錄,這時候row_number()
基本能夠知足需求。code
除此以外,排序函數均較耗性能,特別是若是對大數據量進行全局排序時,必定要考慮性能問題,非必要狀況下,避免對大數據量進行全局排序。排序