SQL ClickHouse 的 system.parts 的 MergeTree 合并状态检查

1次阅读

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

SQL ClickHouse 的 system.parts 的 MergeTree 合并状态检查

system.parts 里哪些分区正在被 MergeTree 合并

clickhouse 的 MergeTree 表合并是后台异步进行的,但你得知道它有没有卡住、有没有积太多未合并的 parts。直接看 system.partsactive 字段没用——它只表示是否参与查询,不反映合并状态。

真正要看的是 engineMergeTree(或其变种如 ReplacingMergeTree)的表中,part_typeWideCompact、且 marksrows 明显偏小的 part,再结合 modification_timeremove_time 判断是否“该合并却没动”。

  • remove_time = '1970-01-01 00:00:00' 表示该 part 还没被标记删除,大概率是活跃的;如果 remove_time 是未来时间或非零但远早于 modification_time,说明它已被选入合并队列但还没完成
  • 查合并中状态最靠谱的方式是:select * FROM system.merges,它会列出当前所有正在执行的 merge 任务,包括 databasetableelapsedprogress
  • 别只盯着 system.partsactive = 1 ——大量 active = 1 的小 part 堆积,恰恰是合并滞后最典型的信号

system.merges 返回空但查询变慢,可能合并卡在哪儿了

system.merges 没结果,不代表没合并压力。MergeTree 合并受后台线程数、磁盘 IO、内存限制等多层控制,常出现“排队中但没启动”的情况。

这时候要交叉验证:

  • system.metricsBackgroundMergesAndMutationsPoolTaskQueueSize:值 > 0 表示有 merge 任务在等待线程资源
  • system.settings 里的 background_merges_mutations_concurrency_ratiomax_background_merges,确认并发上限没被设成 0 或极低值
  • 检查磁盘空间:system.disksfree_space 是否低于 min_free_disk_space_for_merge(默认 5GB),不足时 merge 会暂停
  • 留意错误日志:clickhouse-server.err.log 里搜 MergeTreemerge,常见报错如 Cannot fetch partToo many parts 都指向具体瓶颈

system.partsrows 总和远大于 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 PARTITIONDROP PART 在生产环境基本不用,除非你清楚每一步的 WAL 和 zookeeper 状态

为什么 optimize TABLE ... DEDUPLICATE 没效果

optimize 命令在 MergeTree 表上本质是“建议合并”,不是强制指令。它能否触发实际 merge,取决于当前合并策略、part 数量、大小差异、以及是否满足 ratio_of_defaults_to_force_deletion_of_non_compact_parts 等隐式条件。

  • ReplacingMergeTreeDEDUPLICATE 只在 merge 发生时才生效;如果当前没有 merge 任务,optimize 就只是返回 “Ok.”,什么也不做
  • 小表(parts
  • optimize 不跨分区工作:如果你只写入一个分区,它不会拉其他分区的 part 来一起 deduplicate
  • 想强制推进,可以临时调大 max_bytes_to_merge_at_max_space_in_pool 并等 system.merges 出现任务,而不是反复执行 optimize

合并状态从来不是某个字段能单点判断的事,它横跨 system.partssystem.mergessystem.metrics 和磁盘日志四层。漏掉任意一层,看到的都是残缺图景。

text=ZqhQzanResources