投影 projection 是什么
投影是 ClickHouse 为表预先维护的一份按特定查询模式组织的隐藏数据集:可以换一种排序方式,也可以预先算好聚合结果。查询命中匹配条件时,优化器会自动改用投影,SQL 完全不用改。它把开销转移到写入与合并阶段,因此是「写多读少」与「读多写少」之间的一个可调旋钮。
基本信息
| 适用平台 | ClickHouse MergeTree 家族(较新版本支持) |
|---|---|
| 定义 | ALTER TABLE t ADD PROJECTION p (SELECT … GROUP BY … ORDER BY …) |
| 物化 | MATERIALIZE PROJECTION 回填已有数据;新写入的数据自动维护 |
| 开关 | optimize_use_projections 默认开启,可会话级关闭做对照测试 |
| 查看 | system.projections 与 EXPLAIN 确认投影是否被采用 |
| 代价 | 每个投影都会随写入同步维护,投影越多写入与合并越重 |
典型使用场景
- 固定聚合查询:看板长期按同一维度分组统计,用投影把聚合结果预先算好
- 排序键切换:同一份数据既按时间又按用户查询,用投影提供第二种顺序
- 明细表上的高频过滤:为常用过滤列建投影,避免每次全量扫描
- 替代物化视图的灵活方案:投影随原表管理,不必维护独立的写入链路
- 试运行验证:先建投影观察查询是否真的改用它,再决定是否保留
定义与验证
定义与验证
-- 定义投影:按用户与日期预先聚合,另带一份有序数据集
ALTER TABLE events
ADD PROJECTION proj_user_day
(
SELECT user_id, toDate(ts) AS d, count() AS cnt
GROUP BY user_id, d
);
-- 已有数据需要显式回填,新写入自动维护
ALTER TABLE events MATERIALIZE PROJECTION proj_user_day;
-- 查询书写方式不变,优化器自动选择投影
SELECT user_id, toDate(ts) AS d, count()
FROM events GROUP BY user_id, d;
-- 用 EXPLAIN 确认读取的是投影而不是原表
EXPLAIN SELECT user_id, toDate(ts) AS d, count() FROM events GROUP BY user_id, d;机制对照
| 机制 | 作用点 | 适用判断 |
|---|---|---|
| 投影 | 表内隐藏数据集,随原表写入维护 | 查询模式固定、希望不改 SQL |
| 物化视图 | 独立目标表,写入时触发计算 | 需要跨表加工或独立管理目标表 |
| 跳过索引 | granule 级摘要,只跳块不重排 | 条件选择性高、数据有一定有序性 |
| 排序键调整 | 改变主索引与物理顺序 | 查询模式单一且长期稳定 |
投影本质是用写入与存储换查询速度:用 EXPLAIN 确认查询确实使用了投影,若优化器没选中,多半是聚合粒度或字段与投影定义不完全匹配。
投影数量要克制:每一个都会在写入时同步维护,过多投影会让合并变慢、写入放大显著,新增前先量化收益。