6.2 Join的翻译路径:MapJoin与ReduceJoin


6.2 Join 的翻译路径:MapJoin 与 ReduceJoin

本节摘要:同一条 JOIN 语句可能被翻译成三条路径之一:小表广播的 MapJoin(免 Shuffle)、两边全量过网络的 Reduce Join、依赖分桶布局的 SortMergeBucket Join(免 Shuffle 的归并)。本节讲三条路径的触发条件、自动转换的参数族与失效原因、MapJoin 的内存风险,以及大表连大表的工程破局。

三条路径,一个决策

第 3 章埋了伏笔:Reduce 端 Join 的代价结构是"两边全量数据都过一次 Shuffle"。翻译器在物理计划阶段有两次机会改写这个结构,形成三条路径:

路径一:MapJoin(广播连接)。小表整表被广播到所有 Map 任务,每个任务在内存里持有小表哈希表,扫大表时逐行查表拼接。大表一行数据都不用过网络,Shuffle 整段消失。

路径二:Reduce Join(Shuffle 连接)。默认路径:两边按连接键 Shuffle,Reduce 端拼接。最通用,也最贵。

路径三:SortMergeBucket Join(分桶归并连接)。两表按连接键分桶且桶内有序时,桶 n 只与对侧桶 n 相遇,两边都排好序,归并扫一遍完成连接。用第 4 章的建表布局换运行期 Shuffle

MapJoin 与 ReduceJoin 的数据流对比

MapJoin 与 ReduceJoin 的数据流对比

自动转换:参数族与失效场景

MapJoin 的触发不靠手写提示(虽然提示仍然存在),主力是自动转换参数族:

SET hive.auto.convert.join = true; -- 总开关 SET hive.auto.convert.join.noconditionaltask.size = 32000000; -- 单表广播字节上限 SET hive.auto.convert.join.noconditionaltask = true; -- 多小表合并转换

判定依据是统计信息里的表大小:小表估计体积低于阈值,整表广播。这带来两类失效:统计过期导致小表被高估(白白走 Shuffle)或大表被低估(广播超内存直接任务失败);阈值与容器内存不成对调整(阈值涨了内存没涨,MapJoin 建哈希表时内存溢出)。排查 MapJoin 相关故障,先 ANALYZE 刷统计,再核对阈值与容器内存的配比。

手工提示仍是兜底手段(分号内提示语法,如 JOIN 提示小表别名),适用于优化器判错的个别场景。提示写错的代价不大(被忽略),但依赖提示掩盖统计问题的做法不可持续——统计健康才是正道。

大表连小表连更小表的多表连接,转换还有一个细节:多个小表可以各自转 MapJoin 合并在同一个 Map 任务里,受 noconditionaltask 总量控制。

MapJoin 的内存账

MapJoin 不是免费午餐,它把 Shuffle 成本换成了内存与广播成本:小表在每个 Map 任务里都有一份完整哈希表,N 个任务就是 N 份。小表 100MB、任务数 1000 时,集群为此消耗的内存是 100GB 量级。因此:

  • 阈值的合理上限由 Map 容器内存决定,经验上不超过容器内存的四分之一到三分之一;
  • 小表"看起来小"不算数,看的是统计字节数(压缩前);
  • 极端倾斜的连接键(某个键占大表一半行数)即使走 Reduce Join 也会把一个 Reduce 任务撑爆,这是下一节倾斜治理的主场。

大表连大表:三条破局思路

两张大表按用户键连接,MapJoin 装不下、没分桶 SMB 无缘、Reduce Join 全量 Shuffle——这是实践里最贵的一类查询。三条思路按改动成本递增:

思路一:先削减再连接。两侧都先过滤到最小必需范围(下推的极致运用)、投影到最小列集(列存红利)、能预聚合的先聚合(明细连明细换成聚合结果连维表)。经常一条查询从"TB 连 TB"变成"GB 连 GB"。

思路二:分桶布局预付代价。两张表都是高频互连的核心表,按连接键分桶、桶内排序,SMB Join 常态化免 Shuffle。第 4.3 节的建表纪律在这里兑现价值——一次性重建成本换每次查询的 Shuffle 免除。

思路三:倾斜键拆解。个别超大键(测试账号、默认渠道)拖垮全局时,把它单独拆出来用 MapJoin 处理(超大键在对侧的匹配行往往很小),其余键正常连接,结果再拼接。下一节把这个手法作为倾斜治理的标准招式展开。

三条路径的 EXPLAIN 速查

路径 计划特征 触发前提 主要风险
MapJoin Map 端出现 MapJoin 算子 无 ReduceSink 小表统计体积低于阈值 内存溢出 广播放大
Reduce Join Reduce 端 Join 两侧各有 ReduceSink 默认 全量 Shuffle 倾斜长尾
SMB Join Map 端 merge join 带 bucket 标记 同键分桶 桶数成倍 桶内有序 统计齐全 布局被破坏时失效

读计划时的动作顺序:先看有没有 Join 在 Map 端(有则确认是 MapJoin 还是 SMB),没有再看 Reduce 端 Join 两侧的 ReduceSink(确认两侧都在过网络),最后对照统计与阈值判断"该转没转"的原因。

本节要点回顾

  • 三条路径:MapJoin 广播免 Shuffle、Reduce Join 通用全量 Shuffle、SMB 用布局换 Shuffle;
  • 自动转换靠统计:阈值判大小,统计过期两头翻车(该转不转与转崩);
  • 内存账:MapJoin 的哈希表按任务数放大,阈值与容器内存成对调;
  • 大表连大表三思路:削减再连、分桶预付、倾斜键拆解,按改动成本递增选用;
  • 速查表:MapJoin 看 Map 端算子、ReduceJoin 看 Reduce 端 Join 加双 ReduceSink、SMB 看 bucket 标记。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U