hive数据倾斜及其解决方案

现在常见的数据倾斜分两种情况,一种是大量的空值导致的,另一种是一对多的情况造成的,下面分别说一下这两种的解决方案。

1.空值

这种情况下比较好解决,有两种解决方式,使用哪一种具体取决于你需不需要主键为空值的该行纪录的其它信息,因为有些时候这些信息也有用处。

下面是伪代码:


1.这种情况在join的时候直接过滤空值,最后给union all上

select * from a join  b on a.id is not null and a.id = b.id

union all

select * from  a where a.id is null;





2.给空值字段取一个字符串常量+随机数

select * from a left outer join b on

case when a.id is null then concat('常量字段',rand()) else a.id end = b.id

个人比较推荐第二种方法,因为其不但 IO 少了,而且作业数也少了,方案 1 中,log 表 读了两次,jobs 肯定是 2,而方案 2 是 1。这个优化适合无效 id产生的数据倾斜,把空值的 key 变成一个字符串加上一个随机数,就能把造成数据倾斜的 数据分到不同的 reduce 上解决数据倾斜的问题。使本身为 null 的所有记录不会拥挤在同一个 reduceTask 了,会由于有替代的 随机字符串值,而分散到了多个 reduceTask 中了,由于 null 值关联不上,处理后并不影响最终结果。

2.一对多的情况

这种也需要细分,一种是小表关联大表,一种是大表关联大表

1.小表关联大表很好解决,直接开启map join就可以

在sql脚本上加上如下参数:

set hive.auto.convert.join=true; //设置 MapJoin 优化自动开启

set hive.mapjoin.smalltable.filesize=25000000 //可以根据情况设定具体值





2.大表关联大表

这种情况下,即使设置了map join,hive也不会把任何一张表广播到map端去进行map join,所以我们可以取只需要关联的数据就可以了。

参考以下情况:a 表是张大表,b表也是张大表,a是一张行为记录表,里面记录了当天用户的所有行为信息,b是用户信息表,记录了系统中所有用户的信息,

但是我们在join的时候不需要用到所有的用户信息,我们在这次关联中只需要当天产生行为信息的用户id就可以了。所以,提前对a表对user_id进行distinct

select /*+mapjoin(x)*/* from  a

left outer join (

 select /*+mapjoin(c)*/ b.*

 from ( select distinct user_id from a ) c join b on c.user_id = b.user_id

) x

on a.user_id = x.user_id;

可能用户信息表里面的用户id有500W,然后当天行为记录表有600W条,但是对应只有15W用户产生着600W条纪录,这样的话,join的复杂度从原来的600W*500W到先在的15W*600W,并且还是在map端进行join,大幅减少reduce的压力。



3.两张表确实有这么多数据要join,可以试试skew join
Skew Join


set hive.optimize.skewjoin = true; 
set hive.skewjoin.key = skew_key_threshold (default = 100000)

hive 在运行的时候没有办法判断哪个key 会产生多大的倾斜,所以使用这个参数控制倾斜的阈值,如果超过这个值,新的值会发送给那些还没有达到的reduce。

判断是否有map join在执行计划中可以参考这篇博客:

https://blog.csdn.net/javastart/article/details/84972927

扫描二维码关注公众号,回复: 11493975 查看本文章

参考资料:

https://www.cnblogs.com/qingyunzong/p/8847597.html

猜你喜欢

转载自blog.csdn.net/a6822342/article/details/100747268