数据倾斜原因及处理

数据倾斜原因和处理?

1原因

1)、key分布不均匀
2)、业务数据本身的特性
3)、建表时考虑不周
4)、某些SQL语句本身就有数据倾斜

操作 情形
group by group by 维度过小,某值的数量过多
Count Distinct 某特殊值过多
Join 大表join小表,其中小表key集中,分发到某一个或几个reduce上的数据远高于平均值

2数据倾斜的解决方案

2.1参数调节(group by造成数据倾斜)
set hive.map.aggr=true 设置在Map端进行聚合
set hive.groupby.skewindata = true实现方法是在group by时启动两个MR job。第一个job会将map端数据随机输入reducer,每个reducer做部分聚合,相同的key就会分布在不同的reducer中。第二个job再将前面预处理过的数据按key聚合并输出结果,这样就起到了均衡的效果

select word,count(word) from wordtest group by wordtest
案例:统计单词数量,假设单词d数据倾斜
with
dt as (select word, num, row_number () over () rn from wordtest where word='d'),
dd as (select rn%3 t, sum (num) total from dt group by rn%3),
df as (select 'd' word, sum (total) total from dd),
dw as (select word , sum(num) total from wordtest where word<>'d' group by word)select * from df union all select * from dw;

2.2 Sql语句优化
如果数据量非常大,执行如select a,count(distinct b) from t group by a;类型的SQL时,会出现数据倾斜的问题。

使用sum...group by代替
select a,sum(1) from (select a,b from t group by a,b) group by a;

2.3空值产生的数据倾斜:

解决方法1:空值不参与关联

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比方法1效率更好,解决方法1中 log读取两次,jobs是2。解决方法2 job数是1 。这个优化适合无效 id 产生的倾斜问题。把空值的 key 变成一个字符串加上随机数,就能把倾斜的数据分到不同的reduce上 ,解决数据倾斜问题。

2.4不同数据类型关联产生数据倾斜
默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分配到一个Reducer中

select * from users a left outer join logs b
on a.usr_id = cast(b.user_id as string)

2.5大表join小表
map join 概念:将其中做连接的小表(全量数据)分发到所有 MapTask 端进行 Join,从 而避免了 reduceTask,前提要求是内存足以装下该全量数据

set hive.auto.convert.join= true
set hive.mapjoin.smalltable.filesize`,当小表小于该值就会启用map join,默认值25000000(25MB)

2.6大表join大表
解决办法1:参数设置

set hive.optmize.skewjoin=true
set hive.skewjoin.key=100000; #默认为100000

hive在运行的时候没有办法判断哪个key会产生多大的倾斜,所以使用这个参数控制倾斜的阀值,如果超过这个值,新的值会发送给那些还没有达到的reduce,一般可以设置成你处理的总记录数/reduce个数的2-4倍都可以接受

解决办法2:从其中一个大表中提取join字段形成小表,再和大表进行join

select * from log a
 left outer join (
    select  d.*
      from ( select distinct user_id from log ) c
      join users d
      on c.user_id = d.user_id
    ) x
  on a.user_id = b.user_id;

你可能感兴趣的:(数据倾斜原因及处理)