Hive 的 Join

1、hive中的join类型:

(1)join :只返回关联上的结果。

(2)left join :返回的记录条数和左表相同,关联不上的字段为null。

(3)right join:返回的记录条数和右表相同,关联不上的字段为null。

(4)full join:返回两个表的记录去重之和,关联不上的字段为NULL。

(5)left semi join:左边表为主表,返回主表的KEY也在副表中的记录。

(6)cross join:返回两表记录的笛卡尔积。

具体:https://www.cnblogs.com/liupengpengg/p/7908274.html

2、普通join的原理

(1) reduce join:也叫common join 或者 shuffle join

  这种join就是两个表的数据量都很大的时候,这时候map执行完毕后,利用 shuffle 将两个表 key 相同的 (key,value) 都放到一个reduce当中,然后进行 join 组合。

  common join的原理是利用map将数据从数据源加载过来,并将on后面的条件当做key,将要查询的字段+tag当做value,其中tag是用来标识value是来自哪一张表。然后通过shuffle,利用key的hash值,将其传输到不同的reduce中。然后在reduce当中按照key进行聚合操作。返回查询结果。

        这其中的弊端就是map端没有预聚合,所有的key,value都要经过网络传输,而所有的聚合操作都在reduce当中,容易发生数据倾斜。

 

3、hive中join的优化:

(1)map join :会将指定表放进内存当中,让所有的map都有小表的拷贝,在map阶段就直接拿另一张表和内存中的表进行join。有一下三种情况使用。

  map join是在小表join大表的场景。先将小表加载到所有节点的内存当中,直接在map阶段,在每个分区中就先进行join,无需在将相同的key shuffle到同一个分区。然后再讲聚合后的结果,shuffle到reduce当中,再进行最终的聚合操作。

       这样做的好处就是使用map端预先join进行预聚合,减少网络传输,减轻reduce压力,解决数据倾斜问题。

a、大表 join 小表:这时候用map join 将小表(<1000行)放进内存中,在map端进行jion数据匹配操作。

b、做不等值 join 操作:(a.x<b.y 或 a.x like b.y 等)

  这种操作如果直接使用map的话,hive会报错,若把不能操作写到where当中,可能造成笛卡尔积,数据异常增大,导致运行过慢甚至不成功。

  因此直接用map join直接在map阶段用内存中的表和另一张表进行join操作。

c、mapjoin结合unionall:遇到时候再研究

参考博客,原理讲的好:https://www.cnblogs.com/qiuhong10/p/7698277.html 

 

(2)SMB(sort-merge-bucket) join:为了解决大表join大表效率慢的问题,使用该join方式 。

原理:在后台重新创建两张分桶表,同一个桶和对应桶进行join。在分桶的时候,已经对join的key进行了排序,两个表对应的桶内的数据可以直接进行jion。分桶其实就是把大表化成了“小表”,然后 Map-Side Join 解决之,这是典型的分而治之的思想。

 这种join需要是通过设置响应参数来实现:

set hive.auto.convert.sortmerge.join=true

set hive.optimize.bucketmapjoin=true;

set hive.optimize.bucketmapjoin.sortedmerge=true;

set hive.auto.convert.sortmerge.join.noconditionaltask=true;  

set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;

 

示例:

测试:一个4000万和一个5000多万的表Join,关联键数据倾斜,并且笛卡尔积,效果明显。

建立小表

create table lxw_test1(id int,name string,date_time string)  
clustered by(id) sorted by(id) into 10 buckets;  

建立大表

create table lxw_test2(id int,name string,date_time string)  
clustered by(id) sorted by(id) into 5 buckets;  

启用桶表

set hive.enforce.bucketing = true;  

往小表中插入4000万条记录

  insert overwrite table lxw_test1  
  select id,name,null    
  from woa_all_user_info_his   
  where pt = '2012-05-28'  
  limit 40000000;  

往大表中插5000多万条记录(woa_all_user_info_his中有5000多万条记录)

 insert overwrite table lxw_test2  
 select id,name,date_time  
 from woa_all_user_info_his  
 where pt = '2012-05-28';  

设置Sort Merge Bucket Map Join的参数

set hive.optimize.bucketmapjoin = true;  
set hive.optimize.bucketmapjoin.sortedmerge = true;  
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;  

ps:此时的状况是Bucket columns==Join Columns==Sort Columns,完全具备具备使用Sort Merge Bucket Map Join的条件。

查询

select /*+ mapjoin(b) */ count(1)  
from lxw_test1 a   
join lxw_test2 b  
on a.id = b.id   

测试结果:

包括insert数据,采用Sort Merge Bucket Map Join的方式耗时10分钟左右。

如果这两个表做普通的join,耗时1个多小时,还跑不完,最后只得Kill掉了!

 

参考博客:http://www.360doc.com/content/19/0828/22/14808334_857638864.shtml

 

posted @ 2019-12-31 10:27  guoyu1  阅读(1010)  评论(0编辑  收藏  举报