Hive去重統計
先說核心:
都會在map階段count,但reduce階段,distinct只有一個, group by 可以有多個進行並行聚合,所以group by會快。
經常在公司還能看到。很多老人用distinct去重,很容易數據量大的時候的數據傾斜。感謝上次沖哥的指正。
相信使用Hive的人平時會經常用到去重統計之類的吧,但是好像平時很少關注這個去重的性能問題,但是當一個表的數據量非常大的時候,會發現一個簡單的count(distinct order_no)這種語句跑的特別慢,和直接運行count(order_no)的時間差了很多,於是研究了一下。
先說結論:能使用group by代替distinc就不要使用distinct,例子:
實際論證
order_snap為訂單的快照表 總記錄條數763191489,即將近8億條記錄,總大小:108.877GB,存儲的是公司所有的訂單信息,表的字段大概有20個,其中訂單號是沒有重復的,所以在統計總共有多少訂單號的時候去重不去重結果都一樣,我們來看看:
統計所有的訂單有多少條條數,一個count函數就可以搞定的sql性能如何。
- DISTINCT
select count(distinct order_no) from order_snap; Stage-Stage-1: Map: 396 Reduce: 1 Cumulative CPU: 7915.67 sec HDFS Read: 119072894175 HDFS Write: 10 SUCCESS Total MapReduce CPU Time Spent: 0 days 2 hours 11 minutes 55 seconds 670 msec OK _c0 763191489 Time taken: 1818.864 seconds, Fetched: 1 row(s)
- GROUP BY
select count(t.order_no) from (select order_no from order_snap group by order_no) t; Stage-Stage-1: Map: 396 Reduce: 457 Cumulative CPU: 10056.7 sec HDFS Read: 119074266583 HDFS Write: 53469 SUCCESS Stage-Stage-2: Map: 177 Reduce: 1 Cumulative CPU: 280.22 sec HDFS Read: 472596 HDFS Write: 10 SUCCESS Total MapReduce CPU Time Spent: 0 days 2 hours 52 minutes 16 seconds 920 msec OK _c0 763191489 Time taken: 244.192 seconds, Fetched: 1 row(s)
結論:第二種寫法的性能是第一種的7.448499541倍
注意到為什么會有這個差異,Hadoop其實就是處理大數據的,Hive並不怕數據有多大,怕的就是數據傾斜,我們看看兩者的輸出信息:
# distinct Stage-Stage-1: Map: 396 Reduce: 1 Cumulative CPU: 7915.67 sec HDFS Read: 119072894175 HDFS Write: 10 SUCCESS # group by Stage-Stage-1: Map: 396 Reduce: 457 Cumulative CPU: 10056.7 sec HDFS Read: 119074266583 HDFS Write: 53469 SUCCESS
使用distinct會將所有的order_no都shuffle到一個reducer里面,這就是我們所說的數據傾斜,都傾斜到一個reducer這樣性能能不低么?
再看第二個,直接按訂單號分組,起了457個reducer,將數據分布到多台機器上執行,時間當然快。
由於沒有手動指定Reduce的個數,Hive會根據數據的大小動態的指定Reduce大小,但是可以手動指定
hive> set mapred.reduce.tasks=100;
