谓词下推与分区裁剪是什么
谓词下推是把 WHERE 里的过滤条件尽可能推到扫描层执行,让存储只返回满足条件的数据;分区裁剪是它在分区表上的具体形式,只读条件命中的分区目录。再往下还有文件与数据块裁剪(靠 ORC/Parquet 的统计信息、湖表的清单统计剪掉不匹配的文件)和列裁剪(只读用到的列)。这几层裁剪决定一次查询要碰多少数据,往往是同一段 SQL 快十倍的直接原因。
基本信息
| 适用平台 | Hive、Spark SQL、Flink SQL、Trino、Doris/StarRocks/ClickHouse、Iceberg/Delta/Hudi 湖表 |
|---|---|
| 三类裁剪 | 分区裁剪、文件与数据块裁剪、列裁剪 |
| 依赖条件 | 表统计信息、文件 min-max 统计、分区元数据 |
| 验证方式 | EXPLAIN 看扫描分区与文件数量,OLAP 看扫描 tablet 数 |
| 常见失效原因 | 分区列被函数包裹、列与常量类型不一致、复杂 OR 条件 |
| 收益 | 扫描数据量与 IO 下降,直接体现为查询耗时缩短 |
典型使用场景
- 按天取数:dt = '2026-10-12' 这类常量等值条件让引擎只读单个分区
- 按月补数:用 dt >= 起始日期 AND dt < 结束日期 的范围写法,避免逐天拼 OR
- 宽表查询只选业务需要的列,靠列裁剪把 IO 降下来
- 湖表查询前先做分区与文件级裁剪,必要时先合并小文件再跑分析
- OLAP 表把高频过滤列放进排序键或前缀索引,缩小实际读取的数据块
可下推与不可下推写法
可下推与不可下推写法
-- 推荐:常量等值,可裁剪到单个分区
SELECT store_id, pay_amt FROM dwd_trade_order_di WHERE dt = '2026-10-12';
-- 推荐:范围条件,可裁剪到区间内的分区
SELECT count(*) FROM dwd_trade_order_di
WHERE dt >= '2026-10-01' AND dt < '2026-11-01';
-- 避免:列被函数包裹,分区裁剪失效,退化为全表扫描
SELECT count(*) FROM dwd_trade_order_di WHERE substr(dt, 1, 7) = '2026-10';
-- 避免:constant 与列类型不一致触发隐式转换,裁剪行为不确定
-- 正确做法是保证两侧类型一致
SELECT count(*) FROM dwd_trade_order_di WHERE dt = '2026-10-12';
-- 验证:看执行计划里实际扫描的分区与文件数
EXPLAIN SELECT store_id FROM dwd_trade_order_di WHERE dt = '2026-10-12';写法与裁剪效果
| 写法 | 能否裁剪 | 影响 |
|---|---|---|
| dt = '2026-10-12' | 可裁剪 | 只扫描命中的单个分区 |
| dt >= A AND dt < B | 可裁剪 | 只扫描区间内分区 |
| substr(dt,1,7) = '2026-10' | 列被函数包裹,失效 | 扫描全部历史分区 |
| 列与常量类型不一致 | 依赖隐式转换 | 裁剪可能完全失效 |
| SELECT * 查宽表 | 列裁剪失效 | IO 量成倍放大 |
确认下推是否生效最直接的办法是看执行计划:Hive 与 Spark 看扫描的分区数和文件数,Doris、StarRocks 看扫描的 tablet 数或分区数,写 SQL 前后对比这两个数字即可。
文件与数据块级裁剪依赖统计信息。ORC 与 Parquet 依赖行组内的 min-max 统计,湖表依赖清单里的文件统计;如果数据文件缺少统计信息,即使分区裁剪正确,单分区内部仍会被整段读取。