CollapsingMergeTree 是什么
CollapsingMergeTree 用一个 Int8 的 Sign 列表达增删:+1 是状态行,-1 是对应的取消行,合并时同排序键的一对行互相抵消,数据量随时间收敛。它适合既要最新状态又保留变更轨迹的流水场景。查询尚未完成折叠的数据时要用 sum(Sign) 修正:指标乘 Sign 再求和,并用 HAVING sum(Sign) > 0 过滤掉已取消的记录。VersionedCollapsingMergeTree 用版本列处理乱序到达。
基本信息
| 引擎参数 | CollapsingMergeTree(sign),sign 取 1 或 -1 |
|---|---|
| 合并行为 | 同排序键的一对 +1/-1 行互相抵消 |
| 读取修正 | sum(指标 * Sign),并按 HAVING sum(Sign) > 0 过滤 |
| 替代变体 | VersionedCollapsingMergeTree(sign, version) |
| 所属系统 | ClickHouse |
典型使用场景
- 保留变更历史:既要最新状态也要轨迹的流水表
- 数据收敛:频繁更新的计数类数据通过抵消控制体积
- 状态表:积分、余额这类需要保留增减记录的场景
- 乱序写入:用带版本列的变体处理到达顺序不确定的数据
- 修正读取:查询未折叠数据时按 Sign 求和还原正确值
建表与读取修正
建表与读取修正
CREATE TABLE page_views
(
user_id UInt64,
views UInt64,
Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY user_id;
-- 变更时写入取消行 + 新状态行(插入顺序遵循官方示例)
INSERT INTO page_views VALUES (1001, 7, 1);
INSERT INTO page_views VALUES (1001, 7, -1), (1001, 8, 1);
-- 未折叠数据按 Sign 修正读取
SELECT user_id, sum(views * Sign) AS v
FROM page_views
GROUP BY user_id
HAVING sum(Sign) > 0;要素读法
| 要素 | 含义 | 注意 |
|---|---|---|
| Sign 列 | 1 有效,-1 取消 | 类型必须是 Int8 |
| 排序键 | 决定哪些行互相抵消 | 与 ORDER BY 定义一致 |
| 抵消 | 合并时成对消掉 | 依赖合并,未合并时仍有多行 |
| 读取修正 | 指标乘 Sign 求和 | 不加修正会重复计数 |
| 版本列 | 判断乱序数据新旧 | 属于 Versioned 变体 |
折叠依赖合并过程,未合并时同一主键会出现多行;业务查询不写 FINAL 时用上面的标准修正写法即可拿到正确结果。
插入顺序错误会导致折叠结果与预期不符,落地前对照官方示例验证一次,尤其是取消行与新状态行的先后顺序。
频繁写入取消行会放大写入量,如果只需要最新状态而不关心变更轨迹,ReplacingMergeTree 更省事。
FINAL 修饰符能在查询时完成折叠,但会带来额外的内存与计算开销;明细量大时优先使用按 Sign 修正的写法。