参考地址: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);