join的原理
hive 执行引擎会将Hql的代码翻译为一个一个的map-「shuffle」-reduce 操作,所以实际上join操作都是基于一个或者多个的mr操作。
对于连续的多表join来说,如果多张表join时使用同一列「字段」作为关联了解,那么这些join则会被翻译成一个reduce任务,否则将会被翻译为多个redude任务。
eg1「会被翻译成一个reduce」:
-- 由于使用的join key「关联字段」是同一列,
-- 会被翻译成一个reduce任务
select
t1.user_id
,t1.user_name
,t2.mem_account
,t3.order_account
from user t1
left outer join member t2
on t1.user_id = t2.mem_id
left outer join order t3
on t1.user_id = t3.user_id
;
eg2「被翻译为多个reduce」:
-- 由于使用的join key「关联字段」是多个列,
-- 会被翻译成多个reduce任务
select
t1.user_id
,t1.user_name
,t2.mem_account
,t3.order_account
from user t1
left outer join member t2
on t1.user_id = t2.mem_id
left outer join order t3
on t2.mem_credit_id = t3.credit_id
;
join的分类
join 在原理上可分为3大类:
1. common join
正常的mapper-shuffle-reduce 过程, 在reduce阶段完成join
2. mapjoin
顾名思义,在map端直接完成join,在本地操作,减少了shuffle操作「主要是网络传输」。
可大大提高效率,当join的表都比较大时,有oom的风险
3. sort merge bucket join 「SMB」
smb是sort merge bucket操作,首先进行排序,继而合并,然后放到所对应的bucket中去。
bucket是hive中和分区表类似的技术,就是按照key进行hash,相同的hash值都放到相同的buck中去。在进行两个表联合的时候。我们首先进行分桶,在join会大幅度的对性能进行优化。也就是说,在进行联合的时候,是table1中的一小部分和table1中的一小部分进行联合,table联合都是等值连接,相同的key都放到了同一个bucket中去了,那么在联合的时候就会大幅度的减小无关项的扫描。
原文链接:
join的执行过程
1. Map阶段
读取源表的数据,map输出是以join on 条件中的列作为key , 如果Jon 的条件有多个列,则将这些关联键的组合作为key。
Map输出的value 为 join之后的集合所需要的列「一般为select 的字段或者是where 条件中需用到的列」,与此同时value中还会包含表的Tag信息,用来标识此value对应的是哪个来源表。
2. shuffle 阶段
根据map阶段的key值进行hash,将key-value的键值对按照hash值推送到不通的reduce中「此操作相当耗时,需要产生较大的网络开销」,这样可确保关联的表中相同的key位于同一个reduce任务中。
3. reduce阶段
根据shuffle 后的key值完成 join 操作 ,在此期间通过Tag识别不通来源表的数据。
网友的流程图画的挺好的,我就不再画了,借此一用。
转载链接:
ps:无任何商业用途,如有冒犯,望及时与我联系。
join的优化策略「实战」
1. mapjoin 优化
基于mapjoin的原理,当大表和小表join时,可使用mapjoin的方式,直接将小表加载到内存中,这样可在map阶段直接完成join操作,极大的提高效率【数倍乃至数十倍的效率提升】
可设置mapjoin的大小、开启mapjoin的转化策略
set hive.mapjoin.smalltable.filesize=300000000; //设置mapjoin小表的文件大小为30M,默认为25M,小表阈值「如果内存够大,也适当调整大一些」
set hive.auto.convert.join=true; //设置自动选择MapJoin,默认是true
2. 数据倾斜优化
多表join时经常会因为key值的缘故发生数据倾斜「一般是空值倾斜」,数据倾斜后会导致某些reducer处理的数据量过大,导致任务长尾。
- 当发生空值倾斜时,需要合理利用rand随机函数将空值打散,产生较多的key值,尽可能的将key值分散在各个节点上,最大效率的发挥分布式计算的优势。
select
a.user_id
,a.user_name
,a.text from log a
left outer join users b
on case when a.user_id is null then concat('hive',rand() )
else a.user_id
end
= b.user_id;
- 当发现关联的表中某些少量的key值数据量特别大时,可以将任务拆分为2部分。
-- 非倾斜数据
select
A.id f
rom A join B
on A.id = B.id where A.id <> 1;
-- 倾斜数据
select
A.id
from A join B
on A.id = B.id
where A.id = 1 and B.id = 1;
3. SMB优化
原理上文中有,不再多说,直接上代码:
-- 设置相关参数
set hive.auto.convert.sortmerge.join=true; -- 设置sortmerge
set hive.optimize.bucketmapjoin = true; -- 设置bucketmapjoin
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;
select
t1.id
,t1.org_level
,t2.emp_id
,t2.emp_name
from biz_organization t1
INNER join biz_emp t2
on t2.ds = 20190810
and t1.id = t2.org_id;
个人看法及感受
join 作为hql中最常使用的操作,有必要对其原理有一个深刻的了解;需要join基本的优化策略有清楚的认识,并且用于实际的工作中,有的优化策略可能并不常见,但是需要在使用中去慢慢体会,用多了自然就理解。