博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Hive的三种Join方式
阅读量:6958 次
发布时间:2019-06-27

本文共 4241 字,大约阅读时间需要 14 分钟。

hot3.png

Hive中就是把Map,Reduce的Join拿过来,通过SQL来表示。

参考链接:

Common/Shuffle/Reduce Join

Reduce Join在Hive中也叫Common Join或Shuffle Join

如果两边数据量都很大,它会进行把相同key的value合在一起,正好符合我们在sql中的join,然后再去组合,如图所示。

Reduce Join

Map Join

1) 大小表连接:

如果一张表的数据很大,另外一张表很少(<1000行),那么我们可以将数据量少的那张表放到内存里面,在map端做join。

Hive支持Map Join,用法如下

select /*+ MAPJOIN(time_dim) */ count(1) fromstore_sales join time_dim on (ss_sold_time_sk = t_time_sk)

 

2) 需要做不等值join操作(a.x < b.y 或者 a.x like b.y等)

这种操作如果直接使用join的话语法不支持不等于操作,hive语法解析会直接抛出错误

如果把不等于写到where里会造成笛卡尔积,数据异常增大,速度会很慢。甚至会任务无法跑成功~
根据mapjoin的计算原理,MapJoin会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配。这种情况下即使笛卡尔积也不会对任务运行速度造成太大的效率影响。
而且hive的where条件本身就是在map阶段进行的操作,所以在where里写入不等值比对的话,也不会造成额外负担。

select /*+ MAPJOIN(a) */a.start_level, b.*from dim_level ajoin (select * from test) bwhere b.xx>=a.start_level and b.xx

 

3) MAPJOIN 结合 UNIONALL

原始sql:

select a.*,coalesce(c.categoryid,’NA’) as app_categoryfrom (select * from t_aa_pvid_ctr_hour_js_mes1) aleft outer join(select * fromt_qd_cmfu_book_info_mes) con a.app_id=c.book_id;

 

速度很慢,老办法,先查下数据分布:

select *from(selectapp_id,count(1) cntfromt_aa_pvid_ctr_hour_js_mes1group by app_id) torder by cnt DESClimit 50;

 

数据分布如下:

NA      6173701292       1182933141       40673814d       20151236b       1846306s       11242465       6752408       6422316       611104t       5969734       5794733       4895167       4759999       373395107580  10508

 

我们可以看到除了NA是有问题的异常值,还有appid=1~9的数据也很多,而这些数据是可以关联到的,所以这里不能简单的随机函数了。而t_qd_cmfu_book_info_mes这张app库表,又有几百万数据,太大以致不能放入内存使用mapjoin。

解决方法:首先将appid=NA和1到9的数据存入一组,并使用mapjoin与维表(维表也限定appid=1~9,这样内存就放得下了)关联,而除此之外的数据存入另一组,使用普通的join,最后使用union all 放到一起。

select a.*,coalesce(c.categoryid,’NA’) as app_categoryfrom --if app_id isnot number value or <=9,then not join(select * fromt_aa_pvid_ctr_hour_js_mes1where cast(app_id asint)>9) aleft outer join(select * fromt_qd_cmfu_book_info_meswhere cast(book_id asint)>9) con a.app_id=c.book_idunion allselect /*+ MAPJOIN(c)*/a.*,coalesce(c.categoryid,’NA’) as app_categoryfrom –if app_id<=9,use map join(select * fromt_aa_pvid_ctr_hour_js_mes1where coalesce(cast(app_id as int),-999)<=9) aleft outer join(select * fromt_qd_cmfu_book_info_meswhere cast(book_id asint)<=9) c--if app_id is notnumber value,then not joinon a.app_id=c.book_id

 

设置:

当然也可以让hive自动识别,把join变成合适的Map Join如下所示

注:当设置为true的时候,hive会自动获取两张表的数据,判定哪个是小表,然后放在内存中

set hive.auto.convert.join=true;select count(*) from store_sales join time_dim on (ss_sold_time_sk = t_time_sk)

SMB(Sort-Merge-Buket) Join

对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。 把表(或者分区)组织成桶(Bucket)有两个理由: (1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。 (2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。

场景:

大表对小表应该使用MapJoin,但是如果是大表对大表,如果进行shuffle,那就要人命了啊,第一个慢不用说,第二个容易出异常,既然是两个表进行join,肯定有相同的字段吧。

tb_a - 5亿(按排序分成五份,每份1亿放在指定的数值范围内,类似于分区表)

a_id
100001 ~ 110000 - bucket-01-a -1亿
110001 ~ 120000
120001 ~ 130000
130001 ~ 140000
140001 ~ 150000

tb_b - 5亿(同上,同一个桶只能和对应的桶内数据做join)

b_id
100001 ~ 110000 - bucket-01-b -1亿
110001 ~ 120000
120001 ~ 130000
130001 ~ 140000
140001 ~ 150000

注:实际生产环境中,一天的数据可能有50G(举例子可以把数据弄大点,比如说10亿分成1000个bucket)。

原理:

在运行SMB Join的时候会重新创建两张表,当然这是在后台默认做的,不需要用户主动去创建,如下所示:

SMB Join

ps: 

1.两个表关联键为id,需要按id分桶并且做排序,小表的分桶数是大表分桶数的倍数。 
2.对于map端连接的情况,两个表以相同方式划分桶。处理左边表内某个桶的 mapper知道右边表内相匹配的行在对应的桶内。因此,mapper只需要获取那个桶 (这只是右边表内存储数据的一小部分)即可进行连接。这一优化方法并不一定要求 两个表必须桶的个数相同,两个表的桶个数是倍数关系也可以 
3.桶中的数据可以根据一个或多个列另外进行排序。由于这样对每个桶的连接变成了高效的归并排序(merge-sort), 因此可以进一步提升map端连接的效率

启用桶表

set hive.enforce.bucketing = true;

设置(默认是false):

set hive.auto.convert.sortmerge.join=trueset 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掉了!

 

总结:

其实在写程序的时候,我们就可以知道哪些是大表哪些是小表,注意调优。

转载于:https://my.oschina.net/gordonnemo/blog/2876021

你可能感兴趣的文章
Linux系统下如何查看及修改文件读写权限
查看>>
win8: IndexedDB
查看>>
移植到Windows CE 的经验
查看>>
android开发学习之ViewPager滑动事件讲解
查看>>
BIEEE 创建多维钻取分析(4)
查看>>
AngularJs表单验证
查看>>
微信分享自定义图片和摘要
查看>>
visio ppt axure AI svg powerdesign xmind
查看>>
【模式匹配】Aho-Corasick自动机
查看>>
ExtJs尝下鲜
查看>>
Nginx配置性能优化
查看>>
Atitit.判断元素是否显示隐藏在父元素 overflow
查看>>
SharePoint 2013 激活标题字段外的Menu菜单
查看>>
Java的异步HttpClient
查看>>
关于android中调用系统拍照,返回图片是旋转90度
查看>>
jQuery页面加载初始化的3种方法
查看>>
python常见环境安装
查看>>
生成随机唯一号码, 比如订单号
查看>>
ETHERNET帧结构
查看>>
CentOS7安装Hadoop2.7完整流程
查看>>