bigywater.tech
ClickHouse 内部原理 · 12

Part 合并:后台 Merge 到底合并了什么

真实用3次乱序INSERT制造3个各自有序但整体乱序的part,用OPTIMIZE FINAL触发真实合并,验证merge到底在做什么。

3→1
真实3个乱序part被合并成1个全局有序part
k路归并
merge本质是对已排序part真实做多路归并

做的事:真实分3次INSERT,故意插乱序数据

代码CREATE TABLE demo.mtest (k UInt64, v String) ENGINE=MergeTree ORDER BY k; INSERT INTO demo.mtest VALUES (3,'c'),(1,'a'); INSERT INTO demo.mtest VALUES (2,'b'),(5,'e'); INSERT INTO demo.mtest VALUES (4,'d');

验证:merge之前,每个part内部有序,但part之间真实是乱的

实测 · 本机执行输出(merge前,3个part)
SELECT name, rows, level FROM system.parts WHERE table='mtest' AND active ORDER BY name;
→ all_1_1_0   2 rows   level=0
  all_2_2_0   2 rows   level=0
  all_3_3_0   1 rows   level=0

SELECT _part, k, v FROM demo.mtest ORDER BY _part, k;
→ all_1_1_0 | 1 | a
  all_1_1_0 | 3 | c
  all_2_2_0 | 2 | b
  all_2_2_0 | 5 | e
  all_3_3_0 | 4 | d

每个part内部真实是按ORDER BY k排好序的(all_1_1_0里1排在3前面),但3个part放在一起看,k的顺序真实是1,3,2,5,4——完全不是全局有序。这就是为什么ClickHouse的一次SELECT,即使表定义了ORDER BY,如果直接扫多个part,也需要在读取层面做额外的归并才能保证结果有序。

验证:真实执行OPTIMIZE FINAL,3个part变成1个全局有序的part

实测 · 本机执行输出(OPTIMIZE TABLE demo.mtest FINAL 之后)
SELECT name, rows, level FROM system.parts WHERE table='mtest' AND active;
→ all_1_3_1   5 rows   level=1   ← 真实3个part合并成了1个,level从0变成1

SELECT _part, k, v FROM demo.mtest ORDER BY k;
→ all_1_3_1 | 1 | a
  all_1_3_1 | 2 | b
  all_1_3_1 | 3 | c
  all_1_3_1 | 4 | d
  all_1_3_1 | 5 | e   ← 真实全局有序了
新part的名字all_1_3_1本身就真实记录了这次merge的历史:1_3表示它覆盖了原来block号1到3的三个part,_1(level)表示这是第1层合并产物(原始未合并的part level都是0)。merge真实做的事情,就是把N个各自有序的输入part,按ORDER BY key做一次多路归并(k-way merge),写出一个新的全局有序的大part——这跟归并排序(merge sort)里"合并两个有序子数组"的算法真实是同一件事,只是ClickHouse把它做成了后台异步任务,而不是在每次查询时临时计算。合并完成后,旧的3个part不会立刻删除,而是真实被标记为inactive,等一段时间(默认8分钟,old_parts_lifetime)之后才被后台线程真实清理掉——这也是为什么merge过程中磁盘占用会短暂上涨到"旧数据+新数据"的原因。

分步演示:3个乱序part,真实归并成1个全局有序part

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

merge本质:对多个有序part做真实的多路归并
这一步新验证的状态

    本文用到的工具

    • 本机 ClickHouse 26.9.4(单节点),真实的 system.parts(name/rows/level 列)
    • OPTIMIZE TABLE ... FINAL:真实强制触发一次合并(生产环境后台线程会自动做)
    • _part 虚拟列:真实查看每一行属于哪个part
    京ICP备2026067502号-1京公网安备11010502063487号