HIVE 数据倾斜

HIVE 数据倾斜

1. 什么是数据倾斜

由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点

2. 产生数据倾斜的原因

A:key 分布不均匀
一个表很小,但是key集中;分发到某一个或者几个Reduce上的数据远高于平均值。

B:业务数据本身的特性

C:建表考虑不周全

D:某些 HQL 语句本身就存在数据倾斜

group by
数据维度非常的小,某值的数据非常多;处理某值的reduce非常耗时。

count distinct
某特殊值多,处理此特殊值的reduce非常的耗时

3. 数据倾斜的解决方案

1.参数调节

Map端部分聚合,相当于Combiner
hive.map.agge=true

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)完成计算。

4.典型的业务场景

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 中还可以进行不等值的链接操作,这样可以节省很多的时间,避免笛卡尔积。

4.案例场景:某一特殊key值大量出现,语句中仅出现groupby,没有相应的聚合函数一起
(聚合函数可以在map阶段提前进行聚合,可以降低数据倾斜风险),会造成对应key的reduce出现数据倾斜

解决策略是对key值进行加盐处理:核心实现思路就是进行两阶段聚合。
第一次是局部聚合,先给每个key都打上一个随机数,比如10以内的随机数,此时原先一样的key就变成不一样的了, 比如(hello, 1) (hello, 1) (hello, 1) (hello, 1),就会变成(1_hello, 1) (1_hello, 1) (2_hello, 1) (2_hello, 1)。 接着对打上随机数后的数据,执行sum,count等聚合操作,进行局部聚合,那么局部聚合结果, 就会变成了(1_hello, 2) (2_hello, 2)。然后将各个key的前缀给去掉,就会变成(hello,2)(hello,2), 再次进行全局聚合操作,就可以得到最终结果了,比如(hello, 4)。

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值