bigywater.tech
ClickHouse 内部原理 · 27

SummingMergeTree:聚合结果如何在 Merge 时累加

真实给同一个k分3次插入数值明细,验证SummingMergeTree在OPTIMIZE FINAL之后真实把它们求和成一行汇总记录。

3行→1行
真实merge时把同k的3行明细求和成1行汇总
cnt=3, amt=36
真实求和结果与手算完全一致

做的事:同一个k真实分3次插入,各带一份数值

代码CREATE TABLE demo.smt (k UInt64, cnt UInt64, amt Float64) ENGINE=SummingMergeTree() ORDER BY k; INSERT INTO demo.smt VALUES (1, 1, 10.5); INSERT INTO demo.smt VALUES (1, 1, 20.0); INSERT INTO demo.smt VALUES (1, 1, 5.5);

验证:merge前3行独立存在,OPTIMIZE FINAL之后真实求和成1行

实测 · 本机执行输出
-- merge前
SELECT * FROM demo.smt ORDER BY k;
→ 1  1  5.5
  1  1  20
  1  1  10.5    ← 真实3行分别独立存在,cnt和amt都还没求和

-- 真实执行OPTIMIZE TABLE demo.smt FINAL 之后
SELECT * FROM demo.smt;
→ 1  3  36      ← 真实cnt=1+1+1=3,amt=10.5+20.0+5.5=36,完全对得上

SummingMergeTree真实的行为是:在merge阶段,对ORDER BY指定的排序键完全相同的多行,把除排序键外的所有数值类型列真实按行求和,合并成一行——本文没有显式指定要sum哪些列,ClickHouse真实自动选择了除k之外所有数值类型的列(cnt和amt)参与求和,结果1+1+1=3、10.5+20.0+5.5=36.0真实分毫不差。

SummingMergeTree真实解决的问题和它的边界

SummingMergeTree真实是为"预聚合"场景设计的——典型用法是应用层不断写入细粒度的增量记录(比如每次下单写一条(商品ID, 数量=1, 金额=39.9)),交给SummingMergeTree在后台merge时自动把同一个商品ID的所有增量真实累加成一条汇总记录,避免应用层自己维护一张需要频繁UPDATE的汇总表。它真实的时机逻辑跟本系列上一篇《ReplacingMergeTree》完全一样:求和只在merge真正发生的时候物理执行,在此之前普通SELECT会看到多条尚未求和的明细行,如果业务需要"任何时刻查询都拿到已经求和的结果",要么用SELECT ... FINAL(查询时临时求和,不改变磁盘数据),要么在SELECT里自己再套一层GROUP BY k, sum(cnt), sum(amt)做二次聚合兜底——因为哪怕merge已经发生过,只要后续还有新的INSERT写入同一个k,就会真实产生新的、尚未参与过求和的part,永远存在"最近写入的数据还没被merge进已有汇总"这个真实的时间窗口。

分步演示:从3行明细到merge时真实求和

每一步都是本文上面用真实SummingMergeTree跑出来的原始结果。

3行明细,merge时真实求和成1行汇总
这一步新验证的状态

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 SummingMergeTree()(自动选择数值列求和)
    京ICP备2026067502号-1京公网安备11010502063487号