Hive Sort Merge Bucket Map Join(大表关联)

本文介绍如何通过Hive桶(bucket)提高JOIN操作的效率。通过合理设置表的桶数及排序,可以有效减少JOIN的数据量,进而提升查询速度。文中通过实例展示了小表和大表在分桶和排序后的JOIN操作优化。

Hive 桶

对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive也是 针对某一列进行桶的组织。Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
把表(或者分区)组织成桶(Bucket)有两个理由:

(1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。

(2)使取样(sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。

测试:一个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;  

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

启用桶表
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掉了!

<think>嗯,用户想了解Hive中小joinjoin的区别、原理和应用场景。从用户的提问来看,ta应该有一定的Hive基础,但对底层优化机制需要更系统的梳理。用户引用的资料涉及MapJoin、参数配置、分区分桶等概念,说明ta关注的是性能优化层面的实现细节。 用户可能正在处理实际ETL任务中的数据倾斜问题,或者试图理解团队中现有的Hive调优策略。ta特意区分了"小join"和"join"两种场景,说明遇到过因顺序导致的性能差异。有趣的是,引用材料里提到Hive 0.7之后会自动转换MapJoin,但用户仍区分这两种写法,或许ta的集群存在版本差异或参数被手动关闭过。 需要重点解释的是:虽然SQL语法中顺序不影响逻辑结果,但在Hive物理执行时,明确小在前能直接触发MapJoin。引用[1]的MapJoin架构图和参数hive.mapjoin.smalltable.filesize是核心,要强调25MB默认值这个具体阈值。引用[2]的多join补充说明也很关键,特别是hive.auto.convert.join.noconditionaltask.size这个三级参数容易被忽略。 对于原理部分,准备用分布式计算的视角解释:Common Join在Reduce阶段做连接时,所有数据都要经过Shuffle,而MapJoin能把小全集广播到每个Mapper内存直接匹配。引用[4]的left semi join示例可以衍生说明——这种特殊连接其实也是种MapJoin优化,因为它只需判断存在性而不传输右数据。 用户没问但可能需要的隐藏知识是:当"小"略超25MB时,可以尝试调参数或启用hive.auto.convert.join.use.nonstaged(引用[2]末尾),该参数允许直接使用HDFS文件而非内存暂存。不过要提醒风险,过的"小"可能撑爆容器内存。 最后的场景建议要具体,比如维度关联事实MapJoin,万亿级日志互连则用分桶Join。突然想到引用[3]的分区分桶内容虽然没直接关联,但可以提一句:被分桶的即使作为主,也可能触发Sort Merge Bucket Join来避免Shuffle。 </think>在Hive中,**小 JOIN ** 和 ** JOIN** 的核心区别在于执行策略和性能优化,尤其在数据倾斜场景下现显著。以下是详细解析: --- ### **一、核心区别与原理** #### **1. 小 JOIN (优先触发 Map Join)** - **原理**: 当小(默认 ≤ 25MB)与关联时,Hive 自动通过参数 `hive.auto.convert.join=true` 启用 **Map Join**。 - **执行流程**: 1. 将小全量加载到每个 Mapper 任务的内存中(通过 Distributed Cache)。 2. 数据在 Map 阶段直接与小内存数据进行关联,**跳过 Shuffle 和 Reduce 阶段**。 - **配置参数**: - `hive.mapjoin.smalltable.filesize`:定义小阈值(默认 25MB)[^1]。 - `hive.auto.convert.join`:是否自动转换 Map Join(默认 true)[^1]。 - **优势**: - 避免 Shuffle 产生的网络和磁盘 I/O 开销。 - 彻底解决数据倾斜问题(因无 Reduce 阶段)。 #### **2. JOIN(需手动优化)** - **原理**: 若将写在 JOIN 左侧(` LEFT JOIN`),Hive 可能误判为互连,**退化为 Common Join**(需 Shuffle + Reduce)。 - **风险**: - 数据分发到 Reduce 时易引发数据倾斜(如关联键分布不均)。 - Shuffle 阶段成为性能瓶颈。 - **强制优化**: - **显式指定 Map Join**: ```sql SELECT /*+ MAPJOIN(small_table) */ large_table.col1, small_table.col2 FROM large_table JOIN small_table ON large_table.key = small_table.key; ``` - **调参扩容**: 若小略超 25MB,可临时调 `hive.mapjoin.smalltable.filesize`。 #### **3. 多 JOIN 的优化策略** 当多关联且均为小时(如总小 < 10MB),Hive 会合并为单个 Map Join: - `hive.auto.convert.join.noconditionaltask.size`:控制多合并的阈值(默认 10MB)[^2]。 --- ### **二、应用场景对比** | **场景** | **推荐策略** | **原因** | |-------------------------|-----------------------|--------------------------------------------------------------------------| | **事实 JOIN 维度** | 小(维度)放右侧 | 维度通常较小,自动触发 Map Join | | **互连** | 避免直接 JOIN | 优先考虑分桶 Join 或 预处理过滤数据 | | **存在数据倾斜** | 强制 Map Join 或 SMB Join | 规避 Reduce 阶段的数据倾斜风险 | | **高选择性过滤** | 先过滤再 JOIN | 减少参与 JOIN 的数据量(如 `WHERE` 提前) | --- ### **三、高级优化技巧** 1. **分桶(Bucketing)优化互连** - 对两张关联键分桶(相同桶数),启用 **Sort Merge Bucket Join (SMB Join)**: ```sql SET hive.auto.convert.sortmerge.join=true; SET hive.optimize.bucketmapjoin=true; ``` **原理**:相同桶号的数据直接关联幅减少 Shuffle 数据量[^3]。 2. **处理超“小”** - 若小略超 25MB,启用 `hive.auto.convert.join.use.nonstaged` 直接使用 HDFS 文件(避免内存暂存)[^2]。 3. **半连接(LEFT SEMI JOIN)替代 IN** - 仅需判断右存在性时(无需右字段),使用 `LEFT SEMI JOIN` 比 `IN + JOIN` 更高效: ```sql -- 等效:SELECT * FROM A WHERE A.key IN (SELECT key FROM B) SELECT * FROM A LEFT SEMI JOIN B ON A.key = B.key; -- 结果中不包含 B 的字段[^4] ``` --- ### **四、总结:最佳实践** - ✅ **小永远放 JOIN 右侧**:确保触发 Map Join。 - ✅ **互连时分桶**:启用 SMB Join 优化性能。 - ✅ **主动监控参数**:调整 `hive.mapjoin.smalltable.filesize` 适应实际数据分布。 - ❌ **避免驱动小**:防止 Common Join 导致性能退化。 > 通过合理利用 Map Join 与分桶策略,可显著提升 Hive关联场景下的执行效率,尤其在海量数据环境下效果显著[^1][^3]。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值