Hive中row_number()、dense_rank()、rank()的區別
阿新 • • 發佈:2020-06-10
## 摘要
本文對Hive中常用的三個排序函式```row_number()```、```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()```基本可以滿足需求。
除此之外,排序函式均較耗效能,特別是如果對大資料量進行全域性排序時,一定要考慮效能問題,非必要情況下,避免對大資料量進行全域性
函式 | 共同點 | 不同點 |
row_number() | 用於特定場景下實現排序需求; 均從1開始排序 | 無重複排名(相同排名的按序排名) |
dense_rank() | 有相同排名,但不會跳過佔用的排名 | |
rank() | 有相同排名,但會跳過佔用的排名 |