ClickHouse 表引擎深入
概述
表引擎决定数据如何存储、合并与查询。ClickHouse 以 MergeTree 为基座衍生出去重(Replacing)、预聚合(Summing/Aggregating)等变体,加上 Distributed 分布式表构成完整体系。本文逐一讲透。
一、引擎体系
MergeTree(基座)
├── ReplacingMergeTree(去重)
├── SummingMergeTree(求和预聚合)
├── AggregatingMergeTree(聚合预聚合)
├── CollapsingMergeTree(折叠删除)
└── VersionedCollapsingMergeTree(版本折叠)
分布式:Distributed(集群表)| 引擎 | 核心能力 |
|---|---|
| MergeTree | 分区 + 排序 + 稀疏索引 |
| Replacing | 同排序键去重 |
| Summing | 数值列求和合并 |
| Aggregating | 任意聚合函数预聚合 |
二、MergeTree(基座)
sql
CREATE TABLE events (
event_date Date,
event_type String,
count UInt64
) ENGINE = MergeTree
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, event_type)
SETTINGS index_granularity = 8192;| 参数 | 说明 |
|---|---|
| PARTITION BY | 分区键 |
| ORDER BY | 排序键(主键基础) |
| index_granularity | 索引粒度 |
| SETTINGS | 表级配置 |
适用:通用明细存储三、ReplacingMergeTree(去重)
3.1 作用
合并时,相同排序键只保留一条:
适合"最后状态"类数据(如最新快照)sql
CREATE TABLE user_last (
user_id UInt64,
name String,
updated_at DateTime
) ENGINE = ReplacingMergeTree(updated_at) -- 取最新
ORDER BY user_id;| 要点 | 说明 |
|---|---|
| 去重键 | ORDER BY 字段 |
| 保留 | 默认保留一条(可指定版本列取最新) |
| 合并时 | 后台合并时去重 |
3.2 注意
| 注意 | 说明 |
|---|---|
| 非实时去重 | 合并前查询可能见重复 |
| 强制合并 | OPTIMIZE FINAL |
| 适用 | 可容忍短暂重复 |
四、SummingMergeTree(求和预聚合)
4.1 作用
合并时,数值列自动求和:
明细 → 汇总(减少数据量)sql
CREATE TABLE page_sum (
page_date Date,
page String,
pv UInt64,
uv UInt64
) ENGINE = SummingMergeTree()
ORDER BY (page_date, page);| 要点 | 说明 |
|---|---|
| 求和列 | 除排序键外数值列 |
| 合并 | 同排序键求和 |
| 效果 | 数据量骤减 |
4.2 使用
写入明细 → 后台合并成汇总
查询返回已是汇总(近似实时)| 适用 | 说明 |
|---|---|
| 计数类 | PV/点击量 |
| 求和类 | 金额/时长 |
| 注意 | 查询仍需 SUM(合并非全量) |
五、AggregatingMergeTree(聚合预聚合)
5.1 作用
支持任意聚合函数(sum/avg/uniq 等):
用 AggregateFunction 类型存储中间状态sql
CREATE TABLE agg_events (
event_date Date,
city String,
pv AggregateFunction(sum, UInt64),
uv AggregateFunction(uniq, UInt64)
) ENGINE = AggregatingMergeTree()
ORDER BY (event_date, city);5.2 写入与查询
sql
-- 写入(聚合状态)
INSERT INTO agg_events
SELECT event_date, city,
sumState(count), -- 状态化写入
uniqState(user_id)
FROM events GROUP BY event_date, city;
-- 查询(聚合状态展开)
SELECT event_date, sumMerge(pv), uniqMerge(uv)
FROM agg_events GROUP BY event_date;| 函数 | 说明 |
|---|---|
| sumState/sumMerge | 状态写入/展开 |
| uniqState/uniqMerge | 去重状态 |
| avgState/avgMerge | 均值 |
| 适用 | 说明 |
|---|---|
| 超大规模聚合 | 亿级以上 |
| 复杂去重 | uniq 状态 |
| 注意 | 需状态化函数 |
六、CollapsingMergeTree(折叠)
6.1 作用
用符号(+1/-1)标记行,合并时正负抵消:
支持高效删除/更新sql
CREATE TABLE collapsible (
key UInt64,
sign Int8, -- 1 或 -1
value UInt64
) ENGINE = CollapsingMergeTree(sign)
ORDER BY key;| 要点 | 说明 |
|---|---|
| 标记列 | sign(+1 新数据,-1 删除) |
| 合并 | 正负抵消 |
| 查询 | 需 sum(sign) 过滤 |
适用:需要更新/删除的计费、库存场景七、分布式表(Distributed)
7.1 作用
集群内多分片统一查询入口:
本地表(各节点)+ 分布式表(入口)sql
-- 各节点建本地表
CREATE TABLE events_local ON CLUSTER cluster
(event_date Date, count UInt64)
ENGINE = MergeTree()
ORDER BY event_date;
-- 建分布式表
CREATE TABLE events_distributed ON CLUSTER cluster
AS events_local
ENGINE = Distributed(cluster, default, events_local, rand());| 参数 | 说明 |
|---|---|
| cluster | 集群名 |
| database | 库名 |
| 本地表 | 实际数据 |
| 分片键 | 分布策略(rand/列哈希) |
7.2 读写
写:写分布式表 → 按分片键路由到各节点
读:分布式表 → 各分片并行查 → 合并| 特点 | 说明 |
|---|---|
| 透明 | 应用无感 |
| 并行 | 分片并行 |
| 就近 | 读写本地 |
八、引擎选型
| 场景 | 引擎 |
|---|---|
| 明细存储 | MergeTree |
| 最新状态 | ReplacingMergeTree |
| 计数汇总 | SummingMergeTree |
| 超大聚合 | AggregatingMergeTree |
| 更新删除 | CollapsingMergeTree |
| 集群查询 | Distributed |
| 选型原则 | 说明 |
|---|---|
| 先定业务 | 明细/汇总/去重 |
| 再选引擎 | 匹配能力 |
| 组合使用 | 多引擎协同 |
常见问题速查
| 问题 | 原因与处理 |
|---|---|
| 重复数据 | 用 Replacing/折叠引擎 |
| 查询未预聚合 | 检查聚合引擎与状态函数 |
| 分布式写不均 | 分片键设计 |
| part 过多 | 合并压力,调整分区 |
| 更新删除难 | 折叠引擎或重写 |