Hive join 数据倾斜的一个case优化
Table of Contents

问题

设有一个关于用户信息表A,用户ID字段为uid,存在少量(<1000)uid有大量记录(>100000),使得表A和其他表以uid为key做JOIN的时候,存在数据倾斜。

uid |  f1  | f2
1   |  xx  | yy
1   |  xx  | yy
2   |  xx  | yy

解决方案

思路一:在WHERE条件中过滤掉那些导致数据倾斜的uid。

可以解决,但是如果这种uid太多,或者每天会随时间变化,那么这种硬编码的方法并不通用。

思路二:利用skewjoin的优化选项

set hive.optimize.skewjoin=true;
set hive.skewjoin.key=1000;   

将一个join操作变为两个,第一个会将同一个key分散到不同的reduce,从而解决JOIN时数据倾斜问题。hive.skewjoin.key要设置为需要分散的key最少条数,默认10W条才会做这个操作。

思路三:利用 JOIN 过滤掉那些导致倾斜的uid

根据上述思路,写下如下代码

select A.* from A
JOIN (
    select uid as guid from A
    group by uid
    having sum(1) < 1000
) B
ON A.uid=B.guid

B表用于选择满足条件的uid,然后通过JOIN过滤!问题来了,这个过滤也是JOIN,所以仍然会有数据倾斜的问题!!

由于这样的uid总体上来说比较少,而问题的关键出在不能有JOIN的REDUCE操作,所以可以利用MAPJOIN来解决

select A.* from A
LEFT OUTER JOIN (
    select uid as guid from A
    group by uid
    having sum(1) > 1000
) B
ON A.uid=B.guid
WHERE B.guid is null

注意这里的B表是一个小表,可以通过MAPJOIN优化使得这个LEFT OUTER JOIN没有reduce操作,实现在map端过滤,完美解决!