天天看點

hive進階操作(優化,資料傾斜優化)

2019/2/21 星期四

hive進階操作(優化,資料傾斜優化)

分區表/桶表應用,skew,map-join //見hive的基本文法

行列轉換

hive 優化

hive 優化思想

Explain 的使用

經典案例(distinct count)

資料傾斜的原因

操作:

關鍵詞 情形 後果

1、Join 其中一個表較小,但是key 集中分發到某一個或幾個Reduce 上的資料遠高于平均值 ;

2、大表與大表,但是分桶的判斷字段0 值或空值過多這些空值都由一個reduce 處理,非常慢;

3、group by group by 次元過小,某值的數量過多處理某值的reduce 非常耗時

4、Count Distinct 某特殊值過多處理此特殊值的reduce 耗時。

原因小結:

1)、key 分布不均勻

2)、業務資料本身的特性

3)、建表時考慮不周

4)、某些SQL 語句本身就有資料傾斜

表現:

任務進度長時間維持在99%(或100%),檢視任務監控頁面,發現隻有少量(1個或幾個)reduce 子任務未完成。因為其處理的資料量和其他reduce 差異過大。單一reduce 的記錄數與平均記錄數差異過大,通常可能達到3 倍甚至更多。最長時長遠大于平均時長。

資料傾斜的解決方案

1、參數調節:

hive.map.aggr=true

Map 端部分聚合,相當于Combiner

hive.groupby.skewindata=true

有資料傾斜的時候進行負載均衡,當選項設定為true,生成的查詢計劃會有兩個MR Job。第一個MR Job 中,Map 的輸出結果集合會随機分布到Reduce 中,每個Reduce 做部分聚合操作,并輸出結果,這樣處理的結果是相同的Group By Key 有可能被分發到不同的Reduce 中,進而達到負載均衡的目的;第二個MR Job 再根據預處理的資料結果按照Group By Key 分布到Reduce 中(這個過程可以保證相同的Group By Key 被分布到同一個Reduce 中),最後完成最終的聚合操作。

2、SQL 語句調節:

如何Join:

關于驅動表的選取,選用join key 分布最均勻的表作為驅動表

做好列裁剪和filter 操作,以達到兩表做join 的時候,資料量相對變小的效果。

大小表Join:

使用map join 讓小的次元表(1000 條以下的記錄條數) 先進記憶體。在map 端完成reduce.

大表Join 大表:

把空值的key 變成一個字元串加上随機數,把傾斜的資料分到不同的reduce 上,由于null 值關聯不上,處理後并不影響最終結果。

count distinct(不同) 大量相同特殊值

count distinct 時,将值為空的情況單獨處理,如果是計算count distinct,可以不用處理,直接過濾,在最後結果中加1。如果還有其他計算,需要進行group by,可以先将值為空的記錄單獨處理,再和其他計算結果進行union。group by 次元過小:采用sum() group by 的方式來替換count(distinct)完成計算。

特殊情況特殊處理:

在業務邏輯優化效果的不大情況下,有些時候是可以将傾斜的資料單獨拿出來處理。最後union 回去。

典型的業務場景 //生産中遇到的問題解決方法總結

1、空值産生的資料傾斜

場景:如日志中,常會有資訊丢失的問題,比如日志中的user_id,如果取其中的user_id 和使用者表中的user_id 關聯,會碰到資料傾斜的問題。

解決方法1: user_id 為空的不參與關聯(紅色字型為修改後)

select from log a join users b on a.user_id is not null and a.user_id = b.user_idunion allselect from log a where a.user_id is null;

解決方法2 :賦與空值分新的key 值

select * from log a left outer join users b on case when a.user_id is null then concat(‘hive’,rand() ) else a.user_id end = b.user_id;

結論:方法2 比方法1 效率更好,不但io 少了,而且作業數也少了。

解決方法:

1 中log 讀取兩次,jobs 是2。解決方法2 job 數是1 。

這個優化适合無效id(比如-99 , ’’, null 等) 産生的傾斜問題。把空值的key 變成一個字元串加上随機數,就能把傾斜的資料分到不同的reduce 上,解決資料傾斜問題。

2、不同資料類型關聯産生資料傾斜

場景:使用者表中user_id 字段為int,log 表中user_id 字段既有string 類型也有int 類型。當按照user_id 進行兩個表的Join 操作時,預設的Hash 操作會按int 型的id 來進行配置設定,這樣會導緻所有string 類型id 的記錄都配置設定到一個Reducer 中。

解決方法:把數字類型轉換成字元串類型

select * from users a left outer join logs b on a.usr_id = cast(b.user_id as string)

3、小表不小不大,怎麼用map join 解決傾斜問題

使用map join 解決小表(記錄數少)關聯大表的資料傾斜問題,這個方法使用的頻率非常高,但如果小表很大,大到map join 會出現bug 或異常,這時就需要特别的處理。以下例子:

select from log a left outer join users b on a.user_id = b.user_id;

users 表有600w+ 的記錄,把users 分發到所有的map 上也是個不小的開銷,而且map join 不支援這麼大的小表。如果用普通的join,又會碰到資料傾斜的問題。

select /+mapjoin(x)/ from log a left outer join ( select/+mapjoin(c)/d.* from ( select distinct user_id from log ) c join users d on c.user_id = d.user_id ) x on a.user_id = b.user_id;

假如,log 裡user_id 有上百萬個,這就又回到原來map join 問題。所幸,每日的會員uv 不會太多,有交易的會員不會太多,有點選的會員不會太多,有傭金的會員不會太多等等。是以這個方法能解決很多場景下的資料傾斜問題。

總結:

//*****使map 的輸出資料更均勻的分布到reduce 中去,是我們的最終目标。

由于Hash算法的局限性,按key Hash 會或多或少的造成資料傾斜。大量經驗表明資料傾斜的原因是人為的建表疏忽或業務邏輯可以規避的。

在此給出較為通用的步驟:

1、采樣log 表,哪些user_id 比較傾斜,得到一個結果表tmp1。由于對計算架構來說,所有的資料過來,他都是不知道資料分布情況的,是以采樣是并不可少的。

2、資料的分布符合社會學統計規則,貧富不均。傾斜的key 不會太多,就像一個社會的富人不多,奇特的人不多一樣。是以tmp1 記錄數會很少。把tmp1 和 users 做map join 生成tmp2,把tmp2 讀到distribute file cache。這是一個map 過程。

3、map 讀入users 和log,假如記錄來自log,則檢查user_id 是否在tmp2 裡,如果是,輸出到本地檔案a,否則生成<user_id,value>的key,value 對,假如記錄來自member,生成<user_id,value>的key,value 對,進入reduce 階段。

4、最終把a 檔案,把Stage3 reduce 階段輸出的檔案合并起寫到hdfs。

繼續閱讀