多表关联与 Join 优化
概述
多表 Join 是 OLAP 查询的性能关键。MPP 引擎通过数据本地化减少网络传输:Colocate Join(同桶本地 Join)、Bucket Shuffle Join(桶转发)、Broadcast Join(小表广播),配合 Runtime Filter 动态裁剪。本文逐一讲透原理与调优。
一、Join 为什么慢
MPP 多节点:
数据分散在不同 BE
Join 需数据对齐 → 网络传输 → 慢| 开销 | 说明 |
|---|---|
| 数据搬迁 | 跨节点传输 |
| 内存 | Hash Table |
| 倾斜 | 某节点过载 |
优化思路:减少跨节点数据传输二、Broadcast Join
2.1 原理
小表广播到所有节点:
每节点本地 Join
无需数据搬迁大表适用:右表(小表)足够小| 优点 | 缺点 |
|---|---|
| 无搬迁 | 小表才适用 |
| 简单 | 广播成本 |
| 快 | 网络放大 |
2.2 触发条件
| 条件 | 说明 |
|---|---|
| 小表大小 | 低于阈值(如 10MB-100MB) |
| 强制 | 可通过 hint/参数 |
参数:
broadcast_row_limit / 大小阈值
小表放右表(或显式 Broadcast)三、Colocate Join
3.1 原理
分桶键与桶数一致的表:
相同 key 的数据在同一节点
Join 本地进行,零搬迁前提:
两表 DISTRIBUTED BY HASH(相同列) BUCKETS 相同| 优点 | 缺点 |
|---|---|
| 零网络传输 | 分桶需一致 |
| 稳定 | 建表约束 |
| 大表友好 | 适合大表 Join |
3.2 实现
sql
-- 两表用相同分桶键与桶数
CREATE TABLE a (...) DISTRIBUTED BY HASH(user_id) BUCKETS 16;
CREATE TABLE b (...) DISTRIBUTED BY HASH(user_id) BUCKETS 16;
-- Join 时自动 Colocate(同一分组)
PROPERTIES ("colocate_with" = "grp1")| 要点 | 说明 |
|---|---|
| 分桶键 | 相同 |
| 桶数 | 相同 |
| 副本 | 一致布局 |
| 分组 | colocate_with 同组 |
3.3 适用
大表 × 大表:
公共分桶列 Join
如 用户维度 × 用户事实四、Bucket Shuffle Join
4.1 原理
左表分桶数据直接转发给对应右表桶节点:
按分桶 key 路由,无需全量 shuffle适用:左表为分桶表,右表可按 key 路由| 对比 | 全 Shuffle | Bucket Shuffle |
|---|---|---|
| 传输 | 全量 | 桶级 |
| 开销 | 大 | 小 |
| 前提 | 无 | 分桶匹配 |
4.2 触发
优化器自动选择:
左表分桶键 = Join 键 → 可用五、Runtime Filter
5.1 原理
Join 时先算一侧的过滤条件(如小表 key):
构建 BloomFilter/值集合
下发到另一侧提前过滤
减少扫描与传输示例:
SELECT * FROM orders o JOIN users u ON o.uid = u.id
WHERE u.city = '上海'
→ 先过滤用户(上海)
→ 生成 uid 集合
→ 订单表提前过滤 uid5.2 类型
| 类型 | 说明 |
|---|---|
| Bloom Filter | 存在性过滤 |
| Min/Max | 范围过滤 |
| IN 集合 | 等值过滤 |
| 优势 | 说明 |
|---|---|
| 提前裁剪 | 少读数据 |
| 减少传输 | 少数据 |
| 自动 | 优化器启用 |
5.3 配置
| 参数 | 说明 |
|---|---|
| enable_runtime_filter | 开关 |
| runtime_filter_type | 类型 |
| 大小限制 | 过滤器大小 |
六、Join 调优实践
6.1 调优决策
小表 → Broadcast Join
大表×大表 同分桶 → Colocate Join
分桶匹配 → Bucket Shuffle
默认 → Runtime Filter + Shuffle| 场景 | 策略 |
|---|---|
| 维表 Join | Broadcast |
| 事实×事实 | Colocate |
| 通用 | 优化器自动 |
6.2 建表优化
| 建议 | 说明 |
|---|---|
| 分桶键 | 选高频 Join 列 |
| 桶数 | 均衡与并行 |
| 布局 | 相关表一致 |
6.3 查询优化
| 建议 | 说明 |
|---|---|
| 预过滤 | WHERE 提前 |
| 预聚合 | Join 前聚合 |
| 小表右 | Broadcast 方便 |
| EXPLAIN | 检查执行计划 |
EXPLAIN SELECT ...;
→ 观察 Join 方式与过滤七、数据倾斜处理
7.1 问题
热门 key(如大 V 用户):
单节点数据/计算过载| 处理 | 说明 |
|---|---|
| 加盐 | key 加随机后缀分桶 |
| 拆分 | 倾斜 key 单独处理 |
| 两阶段 | 先聚合再汇总 |
| 调整分桶 | 更细粒度 |
八、常见问题排查
| 问题 | 原因与处理 |
|---|---|
| Join 慢 | 检查是否搬迁(EXPLAIN) |
| Colocate 失效 | 分桶不一致 |
| 内存爆 | 小表广播过大 |
| 倾斜 | 热点 key |
| 结果错 | 关联键重复 |
定位流程:
1. EXPLAIN 看 Join 方式
2. 确认分桶/广播
3. 检查倾斜
4. 逐项调优常见问题速查
| 问题 | 要点 |
|---|---|
| 什么时候 Broadcast | 小表 |
| Colocate 前提 | 分桶一致 |
| Runtime Filter 作用 | 提前过滤 |
| Join 慢主因 | 数据搬迁 |
| 倾斜怎么办 | 加盐/拆分 |