一.join操作数据倾斜
1.mapjoin
map join 默认开启
set hive.auto.convert.join = true(0.11版本后默认是true)
set hive.mapjoin.smalltable.filesize=25000000(设置小表的大小,默认就是25M)
不管大小表放左边还是右边,自动将小表放入内存,然后在map端顺序扫描大表跟内存中的数据进行join,没有reduce阶段,没有shuffle
2.类型不一致
关联字段不一致引发的数据倾斜操作有一个a表关联字段是string类型,b表关联字段是bigint类型,将bigint转换为string类型就可以了
select
a.guid,
a.oid,
b.name
from a
join b
on a.guid=cast(b.guid as string)
3.特殊值过多
如null,空,0导致的数据倾斜
可以将特殊值加盐,可以打散到多个reduce中
select
b.guid,
a.oid,
b.name
from a
join b
on (case when a.guid is null or a.guid=0 or a.guid='null' then CONCAT('hive',RAND()) else a.guid end) = b.guid
4.大表join大表skewjoin
1.综合以上几点,先进行 行列过滤,然后有特殊值将特殊值加盐,类型不一致的类型转换一致
除此之外,还可以skewjoin开启join倾斜优化参数
set hive.optimize.skewjoin=true;
set hive.skewjoin.key=100000; --(处理的总记录数/reduce个数)的2-4倍都可以接受
hive 在运行的时候没有办法判断哪个key 会产生多大的倾斜,所以使用这个参数控制倾斜的阈值,如果超过这个值,新的值会发送给那些还没有达到的reduce, 一般可以设置成你处理的(总记录数/reduce个数)的2-4倍都可以接受
原理:
对于skewjoin.key,在执行job时,将它们存入临时的HDFS目录,其它数据正常执行;
对倾斜数据开启map join操作,对非倾斜值采取普通join操作;
将倾斜数据集和非倾斜数据及进行合并操作。
2.先抽样,看key的分布情况,倾斜key都是需要的数据,不能过滤,左表中有大key,右表中每个key只有一条记录,可以将左表倾斜数据和不倾斜数据分开进行mapjoin,就不会发生数据倾斜了,最后将两部分结果合并到一起
如果是右表中相同key有多条记录,然后可以将左表中倾斜数据添加随机数前缀,然后将右表倾斜数据进行膨胀并添加随机数前缀,两部分添加随机数前缀的数据进行join,这样所有倾斜key就被打散到了多个reduce中进行join操作,再去除随机数前缀.让后将左右表不倾斜数据进行jion和去除随机数前缀的数据union到一起.
5.简单的增加 reduce 并行个数
set mapred.reduce.tasks=100;
二.group by操作数据倾斜
1.map端聚合
在map端部分聚合,然后在reduce端全局聚合
set hive.map.aggr = true;
2.开启group by负载均衡参数,会分两阶段聚合
原理如3
set hive.groupby.skewindata=true;
3.在sql中给group by的key加盐
在sql中给group by的key加盐,将key打散到多个reduce中
先聚合一次,然后将第一阶段的结果中key去除随机数,然后再总的聚合.明显第一阶段使相同的key都打散到了多个reduce中,并且拉去到
第二阶段reduce中的数据明显减少,这就是两阶段聚合.
select
user_id,
sum(cts) as s_cts
from
(
select
user_id,
round(rand()*1000) as rk, --根据具体情况设置随机数的范围
count(1) as cts
from group_t
group by user_id,round(rand()*1000) --根据具体情况设置随机数的范围
) t1
group by user_id
4.避免count(distinct)操作
count(distinct)操作是用一个reduce来完成的,如果数据量很大,会导致整个job很难完成
使用sum() group by 代替