SQL篇—Hive数据倾斜(二)
这是面试经常遇到的问题,虽然我还没有机会在实战中面对过。
-
1.参考文章:
Hive的数据倾斜:
https://www.cnblogs.com/qingyunzong/p/8847597.htmlhttps://www.cnblogs.com/kongcong/p/7777092.html
https://www.jianshu.com/p/ab08de658adc -
2.表现:进度卡在99%,某一个reduce子任务总比其他时间长
-
3.易出现数据倾斜的情况
a. join: 其中一个表小,但key集中/分桶的判断字段0值或空值较多
b.group by: 维度过小,某值的数量过多
c. count distinct: 某特殊值过多 -
4.原因:
key分布不均
建表时考虑不周
业务数据本身特性
某些SQL本身 -
5.solution:
a.表小但key集中
产生新的key,对应的数据分布尽可能均匀map join:将其中做连接的小表(全量数据)分发到所有 MapTask 端进行 Join,从而避免reduceTask,前提要求是内存足以装下该全量数据
用法:在select后面添加/* +mapjoin(tablelist)*/提示优化器转化为map join ,通常tablelist是小表,全量发送到内存select /* +mapjoin(a) */ a.id aid, name, age from a join b on a.id = b.id;
Hive0.11版本以后会自动开启mapjoin优化,由两个参数设置:
set hive.auto.convert.join=true; //设置 MapJoin 优化自动开启
set hive.mapjoin.smalltable.filesize=25000000 //设置小表不超过多大时开启 mapjoin 优化但如果小表太大,无法全量发送,那么需要对上述方法进行改进。
如日志表和用户表的连接:select * from log a left outer join users b on a.user_id = b.user_id;
相对于log,user表是小表但量很大,改进:
select /*+mapjoin(x)*/* from log a left outer join ( select /*+mapjoin(c)*/ d.* from ( select distinct user_id from log ) c join users d on c.user_id = d.user_id ) x on a.user_id = x.user_id;
b.空值较多
将空值的key变成字符串+随机数select * from log a left outer join user b on case when a.user_id is null then concat('hive',rand()) else a.user_id end = b.user_id;
c.不同数据类型关联
user表中 user_id 字段为 int,log 表中 user_id 为既有 string 也有 int 的类型, 进行 join 操作的时候,默认的 hash 操作会按照 int 类型的 id 进 行分配,这样就会导致所有的 string 类型的 id 就被分到同一个 reducer 当中select * from user a left outer join log b on b.user_id = cast(a.user_id as string)