參考地址: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都跑完好久了它還在運行。優化
group by形成的傾斜有兩個參數能夠解決:網站
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字段排序,通常這種分佈方式是很傾斜的排序
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);