bigywater.tech
ClickHouse 内部原理 · 45

Projection:一张表为什么可以准备多种排序方式

真实给一张按k排序的表加一个按cat排序的Projection,验证同样的过滤查询从全表扫描降到只读4.9万行的真实效果。

407倍
真实read_rows从2000万降到4.9万
完全透明
真实业务SQL无需改写,优化器自动选择物理排列

做的事:给不在排序键里的cat列,真实准备第二套排序方式

代码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;

验证:真实read_rows从2000万降到4.9万,降了约407倍

实测 · 本机执行输出
加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真实确认走的是projection内部表,不是原表

实测 · 本机执行输出
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
EXPLAIN真实证实了查询优化器自动把这条查询路由到了proj_by_cat这个projection的内部存储,而不是原表——这也是Projection真实最大的卖点:对使用者完全透明,业务方写的SQL还是照常SELECT ... FROM demo.projtest WHERE cat=777,不需要知道底层多了一份按cat排序的副本、更不需要手动改写SQL去指定用哪份数据,ClickHouse自己会判断当前查询用哪份物理排列的数据更划算。这跟本系列前面验证过的"一张表只能有一个ORDER BY主键排序方式"形成互补——本系列《ORDER BY、Primary Key和Partition Key的区别》验证过一张MergeTree表的物理存储顺序是唯一的,Projection真实提供的解法是:允许一张表额外维护若干份按不同顺序排列的完整副本,用磁盘空间和写入时的额外维护成本(每次INSERT/merge都要同步更新所有projection),换取常见的多种查询模式都能各自命中最合适的排序方式,而不用被迫在多个候选的ORDER BY之间只能选一个。

分步演示:从全表扫描到自动命中projection

每一步都是本文上面用真实ADD PROJECTION跑出来的原始结果。

一张表,真实两套物理排列,查询自动挑合适的那份
这一步新验证的状态

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 ALTER TABLE ADD/MATERIALIZE PROJECTION
    • 真实的 EXPLAIN actions=1 确认查询自动路由到projection内部表
    京ICP备2026067502号-1京公网安备11010502063487号