開發人員首先要確認幾點:
需要計算的指標真的需要從資料倉儲的公共明細層來自行彙總嗎?資料團隊開發的公共彙總層是否可以滿足其要求了?
真的需要掃瞄這麼多分割槽嗎?能掃瞄一周的就不掃瞄一年的。
盡量不要使用select * from table這樣的詞語,能指定哪一列就用那一列,盡量新增過濾條件。
輸入檔案不要大量小檔案,小檔案可以先合併成大檔案。
如果以上問題都排完雷了,資料傾斜問題依然存在,那我們繼續往下看~
情形
後果
join
其中乙個表較小,
但是key集中
分發到某乙個或幾個reduce上的資料遠高於平均值
大表與大表,但是分桶的判斷欄位0值或空值過多
這些空值都由乙個reduce處理,灰常慢
group by
group by 維度過小,
某值的數量過多
處理某值的reduce灰常耗時
count distinct
某特殊值過多
處理此特殊值的reduce耗時
key分布不均勻
業務資料本身的特性
建表時考慮不周
某些sql語句本身就有資料傾斜
任務進度長時間維持在99%(或100%),檢視任務監控頁面,發現只有少量(1個或幾個)reduce子任務未完成。因為其處理的資料量和其他reduce差異過大。
單一reduce的記錄數與平均記錄數差異過大,通常可能達到3倍甚至更多。 最長時長遠大於平均時長。
舉例:比如按照經銷商的**商來做group by,那麼有些大經銷商就有很多訂單,而一些小經銷商只有幾個訂單,那麼分配給發大經銷商的reduce task就有許多訂單,所以造成資料傾斜。
解決:引數設定
hive.map.aggr = true
hive.groupby.skewindata=true
在開發過程中,要小心使用count distinct。
舉例:
select count(distinct user) from table
解決:sql優化
由於必須要去重了,所以hive會把所有的map階段輸出都放在乙個reduce上,造成效能問題,所以通過group by再count進行優化。
select count(*)from( select user from table group by user) tmp
舉例:有兩個表,乙個是**商,乙個是訂單,**商的表不會很大,因為**商就這麼點兒人,而訂單的表就很大了。兩個表join一下,就是乙個很經典的大表join小表問題。
解決:mapjoin hint的方式
select /*+mapjoin(b小表)
*/
舉例:有兩個表,a表表示買家賣家的交易彙總表,b表表示賣家的段位評級。想要獲得賣家在各個級別賣家的成交比例。
如某個買家:金冠店:40%,皇冠店:30%,鑽石店:20%,星級店:10%
這兩個表都會很大,超過mapjoin1g的限制,所以需要找其他方法解決。
如果大表和大表進行join操作,則可採用skewjoin
skewjoin原理
對於skewjoin.key,在執行job時,將它們存入臨時的hdfs目錄。其它資料正常執行
對傾斜資料開啟map join操作,對非傾斜值採取普通join操作
將傾斜資料集和非傾斜資料及進行合併操作
該引數為在執行時動態指定資料進行skewjoin,一般和hive.skewjoin.key引數一起使用
set hive.optimize.skewjoin=true; set hive.skewjoin.key=100000;
以上引數表示當記錄條數超過100000時採用skewjoin操作
此思路有兩種途徑:限制行和列限制行的思路是比如不需要join b表全部,只需要join a表中存在的就行,比如過濾掉90天內沒交易過的賣家
限制列的思路是只取需要的字段
解決場景是傾斜的值明確且數量很少,如用null引起的值。
核心是將這些傾斜的值發放到隨機的reduce,具體做法是在join時對這些特殊的值concat隨機數,從而達到隨即分發的目的。
on (case when a.user_id is null then concat('hive',rand()) else a.user_id end) = b.user_id
最徹底的方式就是動態一分為二,將傾斜和不傾斜的值分開處理,如果不傾斜的直接正常join,如果傾斜的找出來做mapjoin,最後結果union all即可。
場景:如日誌中,常會有資訊丟失的問題,比如日誌中的 user_id,如果取其中的 user_id 和 使用者表中的user_id 關聯,會碰到資料傾斜的問題。
解決方法1:user_id為空的不參與關聯
select *from log ajoin users b
on a.user_id is not
null
and a.user_id =b.user_id
union all
select *from log a
where a.user_id is
null;
解決方法2 :賦與空值分新的key值
select *from log aleft 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上 ,解決資料傾斜問題。
場景:使用者表中user_id欄位為int,log表中user_id欄位既有string型別也有int類 型。當按照user_id進行兩個表的join操作時,預設的hash操作會按int型的id來進行分配,這樣會導致所有string型別id的記錄都分 配到乙個reducer中。
解決方法:把數字型別轉換成字串型別
select *from users aleft outer join logs b on a.usr_id = cast(b.user_id as string)
Hive調優 資料傾斜
1 通常情況下,作業會通過input的目錄產生乙個或者多個map任務。主要的決定因素有 input的檔案總個數,input的檔案大小,集群設定的檔案塊大小 目前為128m,可在hive中通過set dfs.block.size 命令檢視到,該引數不能自定義修改 2 舉例 a 乙個大檔案 假設inpu...
hive的調優以及資料傾斜
調優 fectch抓取 select,filter,limit 這個適合老版本,因為老版本hive預設是minimal,現在新版本都是預設more hive set hive.fetch.task.conversion none 轉為mr hive select from emp query id ...
Hive 資料傾斜解決方案(調優)
在做shuffle階段的優化過程中,遇到了資料傾斜的問題,造成了對一些情況下優化效果不明顯。主要是因為在job完成後的所得到的counters是整個job的總和,優化是基於這些counters得出的平均值,而由於資料傾斜的原因造成map處理資料量的差異過大,使得這些平均值能代表的價值降低。hive的...