应查询 system.merges 表获取正在合并的分区,它直接列出所有执行中的 merge 任务;若为空,则需结合 system.metrics 中 backgroundmergesandmutationspooltaskqueuesize、并发设置、磁盘空间及错误日志综合判断合并是否卡住。

查 system.parts 里哪些分区正在被 MergeTree 合并
clickhouse 的 MergeTree 表合并是后台异步进行的,但你得知道它有没有卡住、有没有堆积太多未合并的 parts。直接看 system.parts 的 active 字段没用——它只表示是否参与查询,不反映合并状态。
真正要看的是 engine 为 MergeTree(或其变种如 ReplacingMergeTree)的表中,part_type 为 Wide 或 Compact、且 marks 和 rows 明显偏小的 part,再结合 modification_time 和 remove_time 判断是否“该合并却没动”。
-
remove_time = '1970-01-01 00:00:00'表示该 part 还没被标记删除,大概率是活跃的;如果remove_time是未来时间或非零但远早于modification_time,说明它已被选入合并队列但还没完成 - 查合并中状态最靠谱的方式是:
select * FROM system.merges,它会列出当前所有正在执行的 merge 任务,包括database、table、elapsed、progress - 别只盯着
system.parts的active = 1——大量active = 1的小 part 堆积,恰恰是合并滞后最典型的信号
system.merges 返回空但查询变慢,可能合并卡在哪儿了
查 system.merges 没结果,不代表没合并压力。MergeTree 合并受后台线程数、磁盘 IO、内存限制等多层控制,常出现“排队中但没启动”的情况。
这时候要交叉验证:
- 看
system.metrics中BackgroundMergesAndMutationsPoolTaskQueueSize:值 > 0 表示有 merge 任务在等待线程资源 - 查
system.settings里的background_merges_mutations_concurrency_ratio和max_background_merges,确认并发上限没被设成 0 或极低值 - 检查磁盘空间:
system.disks中free_space是否低于min_free_disk_space_for_merge(默认 5GB),不足时 merge 会暂停 - 留意错误日志:
clickhouse-server.err.log里搜MergeTree或merge,常见报错如Cannot fetch part、Too many parts都指向具体瓶颈
system.parts 里 rows 总和远大于 SELECT count(*) 的原因
这是 MergeTree 合并不及时最直观的表现之一。每个 part 都存着自己的 rows 统计(来自 count.txt 文件),而 SELECT COUNT(*) 是实时去重 + 合并后计算的,所以只要存在大量 inactive 的旧 part,总数就虚高。
- 运行
SELECT sum(rows) FROM system.parts WHERE active = 0 AND database = 'db' AND table = 'tbl',如果这个值很大(比如占 active 总行数 20% 以上),说明历史碎片没清理干净 -
active = 0的 part 不参与查询,但物理文件仍占磁盘,且会拖慢system.parts查询本身(尤其当数量超万) - 注意:
optimize TABLE ... FINAL不会自动删 inactive part,只是触发合并;真正清理依赖后台 merge 完成后自动remove,过程不可控 - 手动清理风险极高,
DETACH PARTITION或DROP PART在生产环境基本不用,除非你清楚每一步的 WAL 和 zookeeper 状态
为什么 optimize TABLE ... DEDUPLICATE 没效果
optimize 命令在 MergeTree 表上本质是“建议合并”,不是强制指令。它能否触发实际 merge,取决于当前合并策略、part 数量、大小差异、以及是否满足 ratio_of_defaults_to_force_deletion_of_non_compact_parts 等隐式条件。
- 对
ReplacingMergeTree,DEDUPLICATE只在 merge 发生时才生效;如果当前没有 merge 任务,optimize就只是返回 “Ok.”,什么也不做 - 小表(parts
-
optimize不跨分区工作:如果你只写入一个分区,它不会拉其他分区的 part 来一起 deduplicate - 想强制推进,可以临时调大
max_bytes_to_merge_at_max_space_in_pool并等system.merges出现任务,而不是反复执行optimize
合并状态从来不是某个字段能单点判断的事,它横跨 system.parts、system.merges、system.metrics 和磁盘日志四层。漏掉任意一层,看到的都是残缺图景。