ClickHouse 查询优化
概述
ClickHouse 查询优化的核心是"少读数据":分区裁剪、稀疏索引、跳过索引减少扫描量,物化视图与 Projection 预计算,JOIN/GROUP BY 策略匹配引擎特性。本文给出可落地的优化手段。
一、优化总览
| 手段 | 减少什么 |
|---|---|
| 分区裁剪 | 分区范围 |
| 主键索引 | 数据块 |
| 跳过索引 | 无关数据块 |
| 物化视图 | 重复计算 |
| Projection | 预聚合 |
| 列裁剪 | 无关列 |
优化思路:能裁剪则裁剪,能预计算则预计算二、索引设计
2.1 排序键设计
规则:
1. 高频等值列在前
2. 范围列次之
3. 前缀匹配生效| 设计 | 说明 |
|---|---|
| 高基数列在前 | 过滤效果差 |
| 低基数+时间 | 常见组合 |
| 多级排序 | 首列优先 |
示例:
按 (city, event_date, event_type) 排序
WHERE city=... AND date=... → 索引生效
WHERE event_type=... → 索引失效(非前缀)2.2 索引粒度
| 参数 | 说明 |
|---|---|
| index_granularity | 默认 8192 |
| 调小 | 定位更精确、索引更大 |
| 调大 | 索引小、粗粒度 |
三、数据跳过索引(Skip Index)
3.1 作用
按列创建额外索引(如 minmax、set、bloom_filter):
跳过不满足条件的数据块sql
CREATE TABLE events (...) ENGINE = MergeTree()
ORDER BY event_date
INDEX idx_city city TYPE set(100) GRANULARITY 2
INDEX idx_user user_id TYPE bloom_filter GRANULARITY 2;| 索引类型 | 适用 |
|---|---|
| minmax | 范围过滤 |
| set | 低基数枚举 |
| bloom_filter | 高基数等值 |
3.2 设计建议
| 建议 | 说明 |
|---|---|
| 高选择性列 | 收益大 |
| 非排序键过滤列 | 主要场景 |
| 粒度 | 2-4 个 granularity |
跳过索引收益:
跳过大量数据块 → 查询大幅加速四、物化视图
4.1 作用
插入数据时自动聚合到视图表:
查询直接读预聚合结果sql
CREATE MATERIALIZED VIEW mv_page_sum
ENGINE = SummingMergeTree()
ORDER BY (page_date, page)
AS
SELECT page_date, page, count() AS pv, uniq(user_id) AS uv
FROM events GROUP BY page_date, page;| 特性 | 说明 |
|---|---|
| 实时 | 插入即聚合 |
| 透明 | 查询读视图 |
| 增量 | 只算新增 |
4.2 使用注意
| 注意 | 说明 |
|---|---|
| 维度固定 | 视图维度定死 |
| 多视图 | 不同维度可建多个 |
| 数据一致性 | 与源表一致 |
物化视图 = 空间换时间:
预聚合存储,查询快五、Projection 投影
5.1 作用
表内定义"备用排序 + 预聚合":
查询自动选择最优投影
无需额外表sql
CREATE TABLE events (...)
ENGINE = MergeTree()
ORDER BY event_date
PROJECTION p_city_uv (
SELECT city, uniq(user_id)
ORDER BY city
);| 对比 | 物化视图 | Projection |
|---|---|---|
| 存储 | 独立表 | 表内 |
| 维护 | 手动 | 自动 |
| 选择 | 手动查 | 自动匹配 |
5.2 使用
写数据时投影同步更新
查询若命中投影 → 走预计算路径六、JOIN 策略
6.1 原则
| 原则 | 说明 |
|---|---|
| 小表在右 | 右表进内存 |
| 优先预聚合 | 减少 Join 数据量 |
| 避免大表 Join | ClickHouse 弱项 |
6.2 优化手段
| 手段 | 说明 |
|---|---|
| join_algorithm | 选择算法 |
| partial_merge_join | 大表分块 |
| global join | 全局广播 |
| 字典 | 维表转字典 |
JOIN 前先过滤/聚合:
WHERE 下推、子查询预聚合七、GROUP BY 优化
7.1 问题
GROUP BY 高基数列 → 内存聚合压力7.2 优化
| 手段 | 说明 |
|---|---|
| 排序键匹配 | 有序分组省内存 |
| 预聚合表 | Summing/Aggregating |
| 物化视图 | 提前聚合 |
| 多阶段聚合 | 先粗后细 |
规则:
排序键对齐 GROUP BY → 最快
维度树 → 上卷查询八、其他优化
8.1 查询语法
| 优化 | 说明 |
|---|---|
| 只查所需列 | 避免 SELECT * |
| LIMIT | 减少返回 |
| PREWHERE | 过滤下推 |
| SAMPLE | 采样查询 |
8.2 配置
| 参数 | 说明 |
|---|---|
| max_threads | 并行线程 |
| max_memory_usage | 内存上限 |
| max_result_rows | 结果限制 |
8.3 冷热数据
TTL 数据过期:
TTL event_date + INTERVAL 90 DAY
分区级删除/冷存储九、优化排查流程
1. EXPLAIN 看执行计划
2. 检查是否命中分区/索引
3. 看读了多少列/多少数据
4. 是否命中物化视图/投影
5. 逐层优化(裁剪 → 预计算 → 配置)EXPLAIN SELECT ... ;
→ 观察表扫描量变化常见问题速查
| 问题 | 原因与处理 |
|---|---|
| 查询不走索引 | 排序键前缀不匹配 |
| 跳过索引无效 | 选择性低/类型不当 |
| 物化视图数据旧 | 检查写入链路 |
| JOIN 慢 | 换算法/预聚合/字典 |
| GROUP BY 内存爆 | 预聚合表或两阶段 |