Hive的join方式

本文介绍了Hive的三种join方式:Shuffle Join,Map Join和SMB Join。Shuffle Join在MapReduce阶段完成,适合大规模数据。Map Join通过广播小表提高效率,适用于小表与大表连接。SMB Join则在大表连接时通过预分区减少数据传输。了解这些特性有助于优化Hive查询性能。

Hive的三种join方式:

Common/Shuffle/Reduce Join(正常/一般情况)
Map Join(大小表join、不等值join、结合union all) 
SMB(Sort-Merge-Buket) Join(大表join大表)

Shuffle Join

  Shuffle Join在Hive中也叫Common Join或Reduce Join。如果两边数据量都很大,它会进行把相同key的value合在一起,然后再去组合。

• Map阶段:
o 读取源表的数据,Map输出时候以Join on条件中的列为key,如果Join有多个关联键,则以这些关联键的组合作为key,Map输出的value为join之后所关心的(select或者where中需要用到的)列;同时在value中还会包含表的Tag信息,用于标明此value对应哪个表
• Shuffle阶段:
o 根据key的值进行hash,并将key/value按照hash值推送至不同的reduce中,这样确保两个表中相同的key位于同一个reduce中
• Reduce阶段:
o 根据key的值完成join操作,期间通过Tag来识别不同表中的数据

Map Join

  Map Join是在Map阶段进行表之间的连接,而不需要进入到Reduce阶段才进行连接,节省了在Shuffle阶段时要进行的大量数据传输,从而起到了优化作业的作用。Hive内置提供的优化机制之一就包括Map Join。

Map Join的原理:
  其原理是broadcast join,即把小表作为一个完整的驱动表来进行join操作。通常情况下,要连接的各个表里面的数据会分布在不同的Map中进行处理。要使Map Join能够顺利进行,就必须满足:除了一份表的数据分布在不同的Map中外,其他连接的表的数据必须在每个Map中有完整的拷贝。Map Join会把小表全部读入内存中,在Map阶段直接拿另外一个表的数据和内存中表数据做匹配 (这时可以使用DistributedCache将小表分发到各个节点上,以供Mapper加载使用),由于在Map时进行了join操作,省去了Reduce运行的效率也会高很多。

Map Join的实现方法:
1)在Map-Reduce的驱动程序中使用静态方法DistributedCache.addCacheFile()增加要拷贝的小表文件。 JobTracker在作业启动之前会获取这个URI列表,并将相应的文件拷贝到各个TaskTracker的本地磁盘上。
2)在Map类的setup方法中使用DistributedCache.getLocalCacheFiles()方法获取文件目录,并使用标准的文件读写API读取相应的文件。

Hive版本区别:
  Hive 0.7之前,需要给出Map Join的指示,Hive才会提供Map Join的优化。Hive v0.7之后的版本已经不需要给出MapJoin的指示就进行优化。它是通过如下配置参数来控制的:set hive.auto.convert.join=true;

Hive 0.11之后,在表的大小符合设置时:

hive.auto.convert.join.noconditionaltask=true;hive.auto.convert.join.noconditionaltask.size=10000;
hive.mapjoin.smalltable.filesize=25000000

默认会把join转换为map join

Hive 0.12版本,缺省状况下Map Join优化是打开的,也就是hive.auto.convert.join=true。Hive还提供另外一个参数:表文件的大小作为开启和关闭MapJoin的阈值:hive.mapjoin.smalltable.filesize=25000000

Map Join适用的场景:
1) 大小表连接
  如果一张表的数据很大,另外一张表很少(<1000行),那么可以将数据量少的那张表放到内存里面,在map端做join。Hive支持Map Join,用法如下:

select / *+ MAPJOIN(time_dim) */ count(1) from 
store_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里会造成笛卡尔积,数据异常增大,速度会很慢甚至任务无法跑成功。根据map join的计算原理,map join会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配。这种情况下即使笛卡尔积也不会对任务运行速度造成太大的效率影响。而且Hive的where条件本身就是在map阶段进行的操作,所以在where里写入不等值比对的话,也不会造成额外负担。

select / *+ MAPJOIN(a) */ 
a.start_level, b.* 
from dim_level a 
join (select * from test) b 
where b.xx>=a.start_level and b.xx<end_level; 

3)map join结合UNIONALL
  某些情况下join特别慢,可以观察数据,取出特殊(数据特别多的)字段范围放在一组,并使用map join与维表关联,放入内存中,除此之外的数据存入另一组,使用普通join,最后union all放到一起。当设置为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 Join

  大表join大表时,SMB join会自动根据相同的字段进行类似分区分桶的操作,将大表拆成更小一点的表再进行join。设置:

set hive.auto.convert.sortmerge.join=true (默认是falseset hive.optimize.bucketmapjoin=true; 
set hive.optimize.bucketmapjoin.sortedmerge=true; 
### Hive Join 使用方法及示例 #### 一、Hive Join 基本概念 Hive 提供了 SQL 类似的查询语言来处理和分析大规模的数据集,支持多种数据连接操作(Join)。这些操作允许用户从多个表中获取相关数据。理解 Hive Join 的原理与机制对于高效地进行数据分析和处理至关重要[^1]。 #### 二、Hive Join 类型及其语法结构 Hive 中常见的 Join 类型有 INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN 和 FULL OUTER JOIN。每种类型的 Join 都有不同的作用范围: - **INNER JOIN**: 返回两个表中共有的记录。 ```sql SELECT a.*, b.* FROM table_a a INNER JOIN table_b b ON a.id = b.id; ``` - **LEFT OUTER JOIN (左外连接)**: 返回左边表中的所有记录,如果右边表中有匹配,则返回匹配的记录;如果没有匹配,则结果为 NULL。 ```sql SELECT a.*, b.* FROM table_a a LEFT OUTER JOIN table_b b ON a.id = b.id; ``` - **RIGHT OUTER JOIN (右外连接)**: 返回右边表中的所有记录,如果左边表中有匹配,则返回匹配的记录;如果没有匹配,则结果为 NULL。 ```sql SELECT a.*, b.* FROM table_a a RIGHT OUTER JOIN table_b b ON a.id = b.id; ``` - **FULL OUTER JOIN (全外连接)**: 只要其中一个表存在匹配,就返回行。当某一边没有匹配时,另一边的结果会填充NULL。 ```sql SELECT a.*, b.* FROM table_a a FULL OUTER JOIN table_b b ON a.id = b.id; ``` 除了上述标准 Join 外,还有特殊的 Map-side Join 或者称为 MapJoin,在某些情况下可以显著提高性能。MapJoin 将较小的一方加载到内存中完成整个过程而不需要 Reduce 过程,从而加快速度[^2]。 ```sql -- 启用 mapjoin 并指定小表作为map端缓存 SET hive.auto.convert.join=true; SELECT /*+ MAPJOIN(small_table) */ big_table.key, small_table.value FROM big_table JOIN small_table ON big_table.key = small_table.key; ``` #### 三、实际应用案例 假设有一个订单表 `orders` 和客户信息表 `customers`, 我们可以通过以下方式查询每个客户的总消费金额: ```sql SELECT c.customer_name, SUM(o.amount) FROM orders o JOIN customers c ON o.customer_id = c.customer_id GROUP BY c.customer_name; ``` 此查询首先通过 customer_id 字段将两张表格相连,接着计算每位顾客所下的订单总额并按姓名汇总显示出来[^3].
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值