避免join中分区剪枝失效,须在join on条件中显式对齐分区字段(如and sales.ds = users.ds),主表分区条件必须放where子句,且分区字段须裸露无函数包装,否则剪枝链断裂导致全表扫描。

因为分区剪枝在JOIN中极易失效,不是加了分区就自动生效——主表或从表一旦没被正确裁剪,就会退化成全表扫描,亿级数据下I/O和Shuffle开销直接爆炸。
JOIN条件里没显式带上分区字段,剪枝就断了
优化器无法跨表推导分区约束,必须靠你手动“对齐”两表的分区逻辑。常见错误是只在WHERE里写ds = '20240101',但JOIN ON里没包含ds列。
- ❌ 错误写法:
SELECT * FROM sales JOIN users ON sales.user_id = users.id WHERE sales.ds = '20240101'→ users表仍扫全量 - ✅ 正确写法:
SELECT * FROM sales JOIN users ON sales.user_id = users.id AND sales.ds = users.ds WHERE sales.ds = '20240101'→ 两表都能裁剪 - ⚠️ 注意:Hive/Spark中
ds STRING和ds DATE类型不一致会触发隐式转换,剪枝链直接断裂
LEFT JOIN里把分区条件放ON里,主表照样全扫
LEFT JOIN的语义决定了主表(左表)不因ON子句里的分区条件而裁剪,只有从表(右表)能受益。这是最容易踩的坑。
- ❌
SELECT * FROM sales a LEFT JOIN users b ON a.id = b.id AND a.ds = '20240101' AND b.ds = '20240101'→a表仍全表扫描 - ✅ 必须把主表分区条件挪到WHERE:
WHERE a.ds = '20240101',才能让a表生效剪枝 - ? 小技巧:用
EXPLAIN PARTITION(MySQL)或EXPLAIN(Spark/Hive)看partitions列,别信直觉
函数包装分区字段,剪枝立刻失效
优化器做的是静态推导,任何运行时计算都会让它放弃裁剪判断。哪怕只是套一层DATE()或CONCAT(),都等于告诉引擎“我也不知道这值落在哪个分区”。
- ❌
WHERE DATE(ds) = '2024-01-01'、WHERE ds > NOW() - INTERVAL 7 DAY、WHERE SUBSTR(ds, 1, 6) = '202401' - ✅ 保持分区字段裸露:
WHERE ds = '2024-01-01'、WHERE ds BETWEEN '2024-01-01' AND '2024-01-05' - ⚠️ MySQL 5.7对
IN ('20240101', '20240102')支持弱,建议优先用范围;8.0+才稳定支持多值IN剪枝
真正决定剪枝成败的,从来不是表有没有分区,而是执行计划里partitions列到底列出了几个分区名——看到十几个甚至上百个,说明你写的SQL已经和没分区一样慢了。











