006.hive語句優化

參考地址:http://www.cnblogs.com/end/archive/2013/01/15/2861448.htmlhtml

hive玩得好很差,在於你對mapreduce理解深不深叻;固然借鑑學習也很重要sql

傾斜分紅group by形成的傾斜和join形成的傾斜學習


假設網站訪問日誌中會記錄用戶的user_id,而且對於註冊用戶使用其用戶表的user_id,對於非註冊用戶使用一個user_id=0表明。那麼鑑於大多數用戶是非註冊用戶(只看不寫),因此user_id=0佔據了絕大多數。而若是進行計算的時候若是以user_id做爲group by的維度或者是join key,那麼個別Reduce會收到比其餘Reduce多得多的數據——由於它要接收全部user_id=0的記錄進行處理,使得其處理效果會很是差,其餘Reduce都跑完好久了它還在運行。優化

1.group by形成的傾斜

group by形成的傾斜有兩個參數能夠解決:網站

  • map 一個是Hive.Map.aggr,默認值已經爲true,意思是會作Map端的combiner。因此若是你的group by查詢只是作count(*)的話,實際上是看不出傾斜效果的,可是若是你作的是count(distinct),那麼仍是會看出一點傾斜效果。
  • reduce 另外一個參數是Hive.groupby. skewindata。這個參數的意思是作Reduce操做的時候,拿到的key並非全部相同值給同一個Reduce,而是隨機分發,而後Reduce作聚合,作完以後再作一輪MR,拿前面聚合過的數據再算結果。

set Hive.optimize.skewjoin = true; 
還有要告訴Hive如何判斷特殊值,根據Hive.skewjoin.key設置的數量Hive能夠知道,好比默認值是100000,那麼超過100000條記錄的值就是特殊值。日誌

code

因此這個參數其實跟Hive.Map.aggr作的是相似的事情,只是拿到Reduce端來作,並且要額外啓動一輪Job,因此其實不怎麼推薦用,效果不明顯。htm

優化思路是: 先替從後統計blog

/*改寫前*/
select a, count(distinct b) as c from tbl group by a;
/*改寫後*/
select a, count(*) as c
from (select distinct a, b from tbl) group by a;

count(distinct ),在數據量大的狀況下,效率較低,由於count(distinct)是按group by 字段分組,按distinct字段排序,通常這種分佈方式是很傾斜的排序

2.join形成的傾斜

join形成的傾斜,就好比上面描述的網站訪問日誌和用戶表兩個表join:

select a.* from logs a join users b on a.user_id = b.user_id;

1.傾斜的單獨處理

另外對於特殊值的處理每每跟業務有關係,因此也能夠從業務角度重寫sql解決。好比前面這種傾斜join,能夠把特殊值隔離開來(從業務角度說,users表應該不存在user_id = 0的狀況,可是這裏仍是假設有這個值,使得這個寫法更加具備通用性):

select a.* from 
(
select a.*
from (select * from logs where user_id = 0)  a 
join (select * from users where user_id = 0) b 
on a.user_id =  b.user_id
union all
select a.* 
from logs a join users b
on a。user_id <> 0 and a。user_id = b.user_id
)t;

2.傾斜的隨機化處理

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

3.字符類型的hash傾斜處理

統一hash規則,int和string的區別?
本質上:
h(1) 和h('1') ,本質上分配到partition上沒有什麼區別,根本就解決不了數據傾斜的問題。

區別在於:
h(10)可能與h(1)產生hash碰撞,由於hash值可能同樣,致使進一步的數據傾斜
而:
h('10') h('1') ,本質上hash不同;可是若是partition數量較小,可能致使分配到同一個partition裏面

HashPartitioner是mapreduce的默認partitioner。
計算方法是
which reducer=(key.hashCode() & Integer.MAX_VALUE) % numReduceTasks

因此下面問題二的優化思路就是這個意思:

問題2:不一樣數據類型id的關聯會產生數據傾斜問題。 一張表s8的日誌,每一個商品一條記錄,要和商品表關聯。但關聯卻碰到傾斜的問題。s8的日誌中有字符串商品id,也有數字的商品id,類型是string的,但商品中的數字id是bigint的。猜想問題的緣由是把s8的商品id轉成數字id作hash來分配reduce,因此字符串id的s8日誌,都到一個reduce上了,解決的方法驗證了這個猜想。 方法:把數字類型轉換成字符串類型 Select * from s8_log a Left outer join r_auction_auctions b On a.auction_id = cast(b.auction_id as string);  

相關文章
相關標籤/搜索