HIVE 動態分區的一個坑

HIVE 動態分區的一個坑
在hive sql中使用動態分區非常方便,也比較常用,但是在使用的過程中會帶來一些問題,比如:在一段sql語句中我需要指定兩個字段當做動態分區,一個字段的基數爲7,另一個爲4,這就是28個分區,我們的sql語句的最後一個job是一個僅有map階段的任務,數據量大有4000個map,這種情況下map任務在往hive分區中寫的時候,每個map幾乎都要產生28個文件,這樣就會產生4000*28個文件,帶來大量的小文件。比如如下一個簡單的sql:

insert overwrite table test1 partition(week,type)
select
    *
from test_table

這個sql只有map任務,在數據量的情況下可能會產生大量的map,導致產生大量的小文件,實際上不僅僅是最後一個job只有map的任務有影響,reduce同樣如此,但是一般情況下reduce的數目不會太大,並且reduce數目比較好控制。

解決方案
1.最後一個階段只有map,若是有reduce的話,把相同分區的數據發送到一個reduce處理,不就解決了麼。因此可以這樣

insert overwrite table test1 partition(week,type)
select
    *
from test_table
DISTRIBUTE BY week,type;

這樣的話產生的文件數就等於分區數目了(在不限制reduce的情況下),文件數目大大減小,但是文件數目也太少了吧,並且由於數據分佈不均勻,分區下的文件大小差異特別大。並且由於不同reduce處理的數據量差異,造成部分reduce執行速度過慢,影響了整體的速度,

2.若是想把數據均勻的分配的reduce上,DISTRIBUTE BY的字段就不能使用分區下的字段,可以使用DISTRIBUTE BY rand(),這樣rand取哈希然後對reduce數目取餘,保證了每條數據分配到所有reduce的可能性是相等的,這樣reduce處理的數據量就是均勻的,在數據量比較大的情況下每個reduce產生的文件數爲動態分區的個數,產生的文件總個數m*分區個數。

set hive.exec.reducers.max=500;
insert overwrite table test1 partition(week,type)
select
    *
from test_table
DISTRIBUTE BY rand();

比如上邊例子就是 500*28個文件,大大減小了文件數。

實際上還有個最笨的方法就是控制map數,但是map數不能夠小於文件數,除非進行文件合併(帶來額外消耗),這樣的話通過這種方法依賴於上個階段的文件數目。並且map數往往難以控制,若是一個每天執行的任務,數據量每天不一樣帶來了不確定性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章