不管是实际工作还是面试中,数据倾斜的问题永远都是不可避免会遇到的。看了一些文章,发现有的给出的hive数据倾斜解决方法里有函数关键词错误的,下面对hive中的数据倾斜用HQL解决的例子做了总结:
例如:
日志-表A :user_id(用户id) event(行为)state(状态) time(时间戳)
用户-表B :user_id(用户id)sex(性别)
一、两个表相互关联,其中一个表批量出现NULL:
现在做 A left join B
(1)假如表A出现了大批量的user_id为NULL,会碰到数据倾斜的问题,而我们又要排除表A中为NULL的数据,那么可以:
select A1.* , B.*
from
(select * from A where user_id is not NULL ) A1
left join B
on A1.user_id = B.user_id
这里在left jorn 前就过滤点NULL
(2)假如表A出现了大批量的user_id为NULL,会碰到数据倾斜的问题,而我们又要查出A中为NULL的数据,那么可以:
给为NULL的user_id替换一个随机数,考虑到user_id可能是数字,为了防止替换的随机数被匹配到,可以增加一个特殊字符'v_':
select A.* , B.*
from A
left join B
on (case when A.user_id is NULL then concat('v_',rand()) else A.user_id end) = B.user_id;
这里把user_id为NULL变成了随机数,就不存在NULL都在一起的情况了。也就解决了数据倾斜
二、两个表互相关联,其中一个是小表(一般小于二三十M),这种情况可以用 map jorn 解决数据倾斜问题,把小表放在内存中
(1)假如 B 表为小表
select /*+ MAPJOIN(B)*/ A.*,B.*
from
A
left join B
on Auser_id =B.user_id
(2)假如B 表很大,不能放入内存。并且A表日志表也很大,但是A表里面全是作弊用户刷量,也就是说A表里面虽然有很多条记录,但是实际 都是几个或是几十个,几百个相同的user_id的记录。那么我们就可以创造出一个小表,然后运用 map jorn:
select /*+mapjoin(C)*/ A.*,C.*
from A
left join
(
select /*+mapjoin(A1)*/ B.*
from ( select distinct user_id from A ) A1
join B
on A1.user_id = B.user_id
) C
on A.user_id = C.user_id;
**这里的C表是个小表--因为之前说了,A表里面都是重复user_id的记录,经过去重 也就几个或是几十个,几百个,关联B 表的信息后 生产C表。然后最后一层 把 C表当小表 运用map jorn
三、两张大表关联,key分布不均
假如:日志A表中的user_id 有个别几个是 作弊刷量用户(这几个user_id的日志记录条数很多),其他的user_id 正常,这样和用户B表关联可能就会出现数据倾斜。解决方案:
可以打散表A。
select
COALESCE(D.user_id,E.user_id),
COALESCE(D.event,E.event),
COALESCE(D.state,E.state),
COALESCE(D.time,E.time),
D.sex,
D.age
from
(
select B.user_id as B_user_id ,B.sex as sex ,B.age as age , A.user_id as user_id ,A.event as event , A.state as state ,A.time as time from
B
left join
(select * from A TABLESAMPLE(BUCKET 1 out of 2 on time) ) C
on B.user_id = C.user_id
) D
left join
(select * from A TABLESAMPLE(BUCKET 2 out of 2 on time) ) E
on D.B_user_id = E.user_id
这是以B表为主表。如果想要得到A表信息。最后可以在加where 条件。
**这里是把A表,按照time字段Hash取模,分成了2 个桶。目的是为了把那些相同的user_id 记录打散,分在两个表里面。(特殊情况下,不好根据字段打散时,也可以新加一列随机数字段,根据随机数打散)
经过两次left jorn 。
COALESCE函数类似 数据库的NVL函数。
示例
下面的语句返回值 258。
SELECT COALESCE( NULL, 258, 1311, 0 )
备注
如果所有参数均为 NULL,则 COALESCE 返回 NULL