使用mapjoin,左边小表,右边大表,在map端进行join,把小表放到了内存,然后扫描大表进行join.没有shuffle,不走reduce.
开启参数:
set hive.auto.convert.join = true(0.11版本后默认是true)
set hive.mapjoin.smalltable.filesize=25000000(设置小表的大小,默认就是25M)
空值太多join时,会把所有key为空值的数据发送到同一个reduce中,发生数据倾斜
解决方法:
select * from logs
join user
on logs.uid is not null and logs.uid=user.uid;
select
*
from logs
left join user
on case when logs.uid is null then concat('',round(rand()*1000)) else logs.uid=user.uid;
可以将热点数据和非热点数据分别进行处理,最后再合并到一起.
比如log表中的uid类型为int,也有string类型.user表中的uid类型为string.
<1>解决
将log表中uid为int类型的数据转换成string,然后进行join
select
*
from log
join user
on cast(log.uid as string)=user.uid;
默认为false,改为true
set hive.groupby.skewindata=true;
任务执行的时候会有两个mr,
第一个mr任务会把map输出的结果集合随机分配到所有reduce中,做部分聚合;
第二个mr任务会根据预处理的结果按照 group by key 分布到reduce中,完成最终的聚合操作.
产生的原因:
key.hashcode()%numReduce 值相同的就分到了同一个reduce中
当某个分组key数据特别大的时候 group by 阶段就会发生数据倾斜.
原始Hql:
select
works,
count(1) as user_cts
from other
group by works;
<1>解决
给原分组key添加随机数聚合一次,然后再去掉随机数再聚合一次
通过控制给key拼接上的随机数的大小范围来控制热点key分发到不同reduce的范围
SELECT
split(t.total)[0] as works,
sum(t.cts) as user_cts
FROM
(
SELECT
CONCAT(works,'_',ROUND(RAND()*1000)) as total,
count(1) as cts
from other group by CONCAT(works,'_',ROUND(RAND()*1000))
) t
group by split(total,'_')[0];