bigywater.tech
ClickHouse 内部原理 · 15

分区裁剪:查询为什么可以跳过大量数据

真实用EXPLAIN indexes=1对比同一张20分区表在分区键过滤和普通列过滤下的Parts裁剪比例,看清楚分区裁剪到底是怎么生效的。

1/20 vs 20/20
分区键过滤真实只扫1个分区,普通列过滤真实全扫
EXPLAIN indexes=1
真实直接看到三层索引各自的裁剪结果

做的事:20个月分区,真实分别用分区键和普通列做过滤

代码CREATE TABLE demo.prune (d Date, k UInt64, v String) ENGINE=MergeTree PARTITION BY toYYYYMM(d) ORDER BY k; INSERT INTO demo.prune SELECT toDate('2026-01-01')+number, number, toString(number) FROM numbers(600); -- 跨度约20个月 EXPLAIN indexes=1 SELECT count() FROM demo.prune WHERE toYYYYMM(d)=202601; EXPLAIN indexes=1 SELECT count() FROM demo.prune WHERE v='300';

验证:命中分区键,真实20个分区只扫1个

实测 · 本机执行输出(WHERE toYYYYMM(d)=202601)
EXPLAIN indexes=1 SELECT count() FROM demo.prune WHERE toYYYYMM(d)=202601;
→ ReadFromMergeTree (demo.prune)
     Indexes:
       Min-Max
         Parts: 1/20        ← 真实20个part只留1个
         Granules: 1/1
       Partition
         Keys: toYYYYMM(d)
         Condition: and((toYYYYMM(d) in (-Inf,202602]), (toYYYYMM(d) in [202601,+Inf)))
         Parts: 1/1          ← 真实分区级别的裁剪:1个分区
         Granules: 1/1

过滤条件toYYYYMM(d)=202601直接命中了分区键的表达式,ClickHouse真实在查询规划阶段就能算出"202601"对应哪一个分区目录,直接跳过其余19个分区,连打开它们的文件都不需要——这就是分区裁剪(Partition Pruning)真实生效的样子:Parts: 1/20意味着20个part里真实只有1个进入了后续的扫描流程。

验证:过滤普通列(非分区键),真实20个分区全扫

实测 · 本机执行输出(WHERE v=\'300\',v不是分区键也不是主键)
EXPLAIN indexes=1 SELECT count() FROM demo.prune WHERE v='300';
→ ReadFromMergeTree (demo.prune)
     Read type: Default
     Parts: 20 | Granules: 20
     Indexes:
       Min-Max
         Condition: true
         Parts: 20/20        ← 真实一个都没裁掉
       Partition
         Condition: true
         Parts: 20/20        ← 真实一个都没裁掉
       PrimaryKey
         Condition: true
         Parts: 20/20
同一张表,唯一的区别是过滤列换成了v(既不是分区键toYYYYMM(d),也不是排序键k),三层索引(Min-Max、Partition、PrimaryKey)的Condition都真实变成了true(意思是"这个索引对这次查询无法提供任何过滤信息"),Parts: 20/20说明20个part真实一个都没被跳过,必须全部打开扫描。这组对比真实印证了上一篇《Partition:按月分区和按天分区怎么选》里官方报错提到的那句话——分区键要真实发挥裁剪作用,前提是WHERE条件里出现的表达式能够真实映射到分区键本身(比如toYYYYMM(d)=202601直接命中PARTITION BY toYYYYMM(d));一旦过滤条件落在其他列上,哪怕这张表本身分了再多分区,也没有任何裁剪收益,反而要承担分区数过多带来的额外开销。

分步演示:EXPLAIN真实拆穿"分区裁剪"是怎么生效的

每一步都是本文上面用真实EXPLAIN indexes=1跑出来的原始结果。

同一张表,分区键过滤 vs 普通列过滤的真实差距
这一步新验证的查询

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 EXPLAIN indexes=1
    • 真实对比Min-Max/Partition/PrimaryKey三层索引在两种过滤条件下的Parts裁剪比例
    京ICP备2026067502号-1京公网安备11010502063487号