Hive数据倾斜,
一、数据倾斜产生原因
1.操作
join
- 一个表很小,但是key集中;分发到某一个或者几个Reduce上的数据远高于平均值。
- 大表与大表,但是字段的空值很多;这些空值都由一个reduce进行操作,速度非常的慢。
group by
- 数据维度非常的小,某值的数据非常多;处理某值的reduce非常耗时。
count distinct
- 某特殊值多;处理此特殊值的reduce非常的耗时。
2.原因
(1)key值分布不均匀。
(2)业务数据本身的问题。
(3)建表时候考虑不周。
(4)某些sql语句的问题,本身就有数据倾斜的问题。
3.表现
各个reduce处理数据所需时间差异性很大。
二、数据倾斜的解决方案
1.参数调节
hive.map.agge=true
Map端部分聚合,相当于Combiner
hive.groupby.skewindata=true
有数据倾斜的时候进行负载均衡,当选项设定为true,生成的查询计划会有两个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:
使用map join 让小的维度表(1000条一下的记录)先进内存,在map端完成reduce,直接拿另一表中的数据与内存中的数据进行匹配。
大表Join大表:
把空值的key变成字符串加上随机数,把倾斜的数据分布到不同的reduce上去,由于null关联不上并不影响最终的输出结果。
count distinct 大量相同的特殊值:
将空值情况单独处理,如果是计算count distinct,直接过滤,最后的结果加上1;如果还有其它计算,需要group by,可以先将空值记录单独处理,然后再和其它的结果进行union。
group by维度过小:
采用count() 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_id
union all
select * 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.不同数据类型关联产生数据倾斜
场景:用户表中user_id为int,log表中的user_id为int和string。当按照user_id进行两个表的join操作的时候,默认的hash操作会按照int类型的id进行分配,这样导致所有的string类型的数据都进入同一个reduce之中,解决的方法如下,把所有的数字类型转换为string的类型:
select * from users a
left outer join logs b
on a.usr_id = cast(b.user_id as string)3.map join 解决大小表结合的问题
场景:A表中有100行的数据,B表中30亿的数据
解决方法:
select /*+ mapjoin(A)*/ f.a,f.b from A t join B f on ( f.a=t.a and f.ftime=20110802) map join 中还可以进行不等值的链接操作,这样可以节省很多的时间,避免笛卡尔积。