首页/数据/数据工程与 ETL 速查/分区裁剪 Partition Pruning
管道基础52 条

分区裁剪 Partition Pruning

查询只需读取命中的分区目录,是数仓查询性能的关键前提。前提是过滤条件直接作用于分区列;对分区列做函数变换会让裁剪失效。

分区裁剪是什么

分区裁剪(Partition Pruning)指查询只读取过滤条件命中的分区目录,跳过其余目录。它是数仓查询性能的第一前提:一张按天分区的表有上千个分区,一次只查一天的查询应该只扫一个目录,而不是全表。前提是过滤条件直接作用在分区列上。

什么写法会让裁剪失效

对分区列做函数变换是最常见的失效原因:把 dt 包进 substr、date_format、cast 之类的表达式后,引擎无法把条件映射到目录名,只能退化为扫描全部分区。类型不一致也会触发隐式转换,同样可能破坏裁剪。

基本信息

原理按分区目录的统计信息跳过无关目录
前提WHERE 中直接出现分区列,使用等值、IN 或范围条件
失效原因对分区列做函数变换、类型隐式转换
验证方式EXPLAIN 中查看扫描的分区数或分区过滤条件
相关优化列式存储的列裁剪与统计信息跳过

分区列写法对错对照

写法能否裁剪说明
WHERE dt = '2026-10-11'能最理想,直接命中单个分区
WHERE dt IN ('2026-10-10','2026-10-11')能命中多个分区
WHERE dt BETWEEN '2026-10-01' AND '2026-10-11'能范围裁剪
WHERE substr(dt,1,7) = '2026-10'不能对分区列做函数运算,退化为全分区扫描
WHERE dt = 20261011可能不能分区列为字符串而传入数字,隐式转换可能破坏裁剪

典型使用场景

  • 报表查询:按业务日期过滤,只扫当天或当月的分区
  • 补数任务:按区间重跑,精确命中受影响分区的集合
  • 巡检核查:用 EXPLAIN 确认线上慢查询是否真的只扫了目标分区
  • 分区设计:把最常用的过滤字段设计成分区列
  • 性能对比:改动前后对比扫描分区数,量化优化效果

可裁剪与不可裁剪

可裁剪与不可裁剪
-- 可裁剪:分区列直接过滤
SELECT COUNT(*) FROM dwd_order WHERE dt = '2026-10-11';

-- 不可裁剪:对分区列做函数运算,退化为全分区扫描
SELECT COUNT(*) FROM dwd_order WHERE substr(dt, 1, 7) = '2026-10';

-- 改写方式:把函数移除,改成显式的范围条件,恢复分区裁剪
SELECT COUNT(*) FROM dwd_order
WHERE dt >= '2026-10-01' AND dt <= '2026-10-31';

-- 验证:EXPLAIN 中观察扫描的分区数量与分区过滤条件
EXPLAIN SELECT COUNT(*) FROM dwd_order WHERE dt = '2026-10-11';
写 SQL 时保持分区列「裸用」是最省事的纪律:任何加工、格式化、类型转换都放到取数之后再做,既保证裁剪,也避免把格式差异带到下游。
动态分区写入未限制分区数可能一次产生大量小分区:任务本身能跑完,但元数据与后续查询规划都会明显变慢,应按数据量控制每次写入的分区数量。

易错点

  • 分区列被函数包裹(substr、date_format 等),裁剪失效退化为全表扫描,查询耗时成倍上升
  • 分区列类型与传入值类型不一致触发隐式转换,是否裁剪取决于引擎实现,表现时好时坏
  • 动态分区写入不限制分区数量,一次产生上千个小分区,元数据与规划耗时一起上升
  • 改动 SQL 后不验证扫描量:只看查询变快,忽略了是否仍有全分区扫描

数据来源与参考

  • Apache Hive 官方文档:Partitioned Tables
  • Apache Spark 官方文档:Partition Discovery
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌