真实给一张按k排序的表加一个按cat排序的Projection,验证同样的过滤查询从全表扫描降到只读4.9万行的真实效果。
代码CREATE TABLE demo.projtest (k UInt64, cat UInt16, amt Float64) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.projtest SELECT number, number%1000, number*1.5 FROM numbers(20000000); -- 加之前 SELECT sum(amt) FROM demo.projtest WHERE cat=777; -- 真实加一个按cat排序的projection ALTER TABLE demo.projtest ADD PROJECTION proj_by_cat (SELECT k, cat, amt ORDER BY cat); ALTER TABLE demo.projtest MATERIALIZE PROJECTION proj_by_cat;
加projection前: read_rows: 20000000 ← 真实全表扫描,因为cat不在ORDER BY k里 query_duration_ms: 17 加并MATERIALIZE projection后: read_rows: 49152 ← 真实只读了约4.9万行 query_duration_ms: 2 真实降幅:20000000 / 49152 ≈ 407倍
加之前,cat不在表的ORDER BY k里,主键索引对cat=777这个条件完全帮不上忙,只能真实全表扫描2000万行去逐行过滤;加了projection之后,ClickHouse在MATERIALIZE阶段真实为表额外准备了一份按cat重新排序的完整副本数据(本质上是同一份数据的另一套物理排列),下次查询遇到按cat过滤的条件,就能真实复用这份副本的稀疏索引,只读真正涉及cat=777的granule。
EXPLAIN actions=1 SELECT sum(amt) FROM demo.projtest WHERE cat=777;
→ Aggregating
└──ReadFromMergeTree (proj_by_cat) ← 真实读的是proj_by_cat,不是demo.projtest原表
Prewhere filter column: cat = 777每一步都是本文上面用真实ADD PROJECTION跑出来的原始结果。
ALTER TABLE ADD/MATERIALIZE PROJECTIONEXPLAIN actions=1 确认查询自动路由到projection内部表