1. 程式人生 > >Hive中row_number()、dense_rank()、rank()的區別

Hive中row_number()、dense_rank()、rank()的區別

## 摘要 本文對Hive中常用的三個排序函式```row_number()```、```dense_rank()```、```rank()```的特性進行類比和總結,並通過筆者親自動手寫的一個小實驗,直觀展現這三個函式的特點。 ## 三個排序函式的共同點與區別
函式 共同點 不同點
row_number() 用於特定場景下實現排序需求;
均從1開始排序
無重複排名(相同排名的按序排名)
dense_rank() 有相同排名,但不會跳過佔用的排名
rank() 有相同排名,但會跳過佔用的排名
## 實驗示例 ```sql 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()```進行排名時,他們的排名會並列,且後續記錄的排名會跳過被佔用的排名數,而不會順延下去。 ## 總結 在實際開發過程中,可根據場景的需要去選擇具體的排序函式。一個較為常見的場景是根據某個欄位```partition by```之後在該範圍內```order by```進行排序,然後取首條記錄,這時候```row_number()```基本可以滿足需求。 除此之外,排序函式均較耗效能,特別是如果對大資料量進行全域性排序時,一定要考慮效能問題,非必要情況下,避免對大資料量進行全域性