ReplacingMergeTree 是什么
ReplacingMergeTree 是 ClickHouse MergeTree 家族中的一个表引擎,用于在后台合并 part 时按排序键去重、只保留版本最新的一行。它解决的是「同一实体反复写入、读取时只关心最新状态」这类问题:写入侧可以无脑追加变更记录,后台合并逐步收敛,读取侧用 FINAL 或手工聚合拿到去重结果。
基本信息
| 引擎参数 | ReplacingMergeTree([ver]),ver 为版本列,缺省时保留最后写入的那一行 |
|---|---|
| 去重范围 | 同一数据分区内、排序键 ORDER BY 完全相同的行;跨分区不去重 |
| 去重时机 | 后台合并时执行,不是写入即去重 |
| 读取保证 | SELECT ... FINAL 强制去重,或 GROUP BY 排序键 + argMax 手工取最新 |
| 复制版本 | ReplicatedReplacingMergeTree 用于副本表,去重语义相同 |
典型使用场景
- CDC 增量同步:源库每条变更写一行,落库后合并自动收敛为最新快照
- 维表全量刷新:每天重复导入同一批主键,读时只取版本最大的记录
- 状态流转审计:保留变更流水,按版本列取最终状态
- 替代「先删后插」的更新方式,避免 DELETE 引发的大范围分区重写
- 作为物化视图的目标表,配合聚合函数实现按主键取最新
建表与读取
建表与读取
CREATE TABLE users
(
id UInt64,
name String,
updated_at DateTime
)
ENGINE = ReplacingMergeTree(updated_at) -- 以 updated_at 为版本列,值越大越新
ORDER BY id; -- 排序键就是去重键
INSERT INTO users VALUES (1, 'alice', now() - 100), (1, 'alice-new', now());
INSERT INTO users VALUES (1, 'alice-older', now() - 200); -- 版本更旧,合并后会被替换
SELECT * FROM users FINAL WHERE id = 1; -- 查询时完成去重
SELECT id, argMax(name, updated_at) AS name FROM users GROUP BY id; -- 手工取最新的等价写法去重行为读法
| 场景 | 行为 | 注意 |
|---|---|---|
| 同分区且排序键相同 | 合并后只保留版本最大的一行 | 合并时机由后台调度决定,可能长时间不触发 |
| 跨分区同排序键 | 不去重,两行都会保留 | 按天分区时同一主键跨天变更会留下多行 |
| 版本列取值相同 | 保留哪一行不确定 | 版本列必须严格递增,精度不够会撞车 |
| 查询不带 FINAL | 可能同时看到新旧多行 | 计数与求和口径会偏大 |
该引擎的去重是最终一致而非即时生效:刚写入的新旧两行在合并前都会出现在查询结果中,所以业务侧要么查询时带 FINAL,要么用 GROUP BY 配合 argMax 兜底,不能假设重复行已经消失。