You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Clickhouse执行Optimize Final后后台合并触发内存超限错误求助

问题描述

我有一张名为T1的表,包含3103个数据分片(part),表总数据量达100亿行,其中约1000个为小分片(行数小于5000),可通过以下SQL查询验证:

select count(rows) from system.parts where table = 'T1' having rows < 5000

查询结果约为1000。

查看system.part_log表发现,后台合并操作因内存不足每秒失败10次,相关错误信息可通过以下SQL获取:

select query_id, event_type, merge_reason, merge_algorithm, duration_ms, partition_id, part_type, length(merged_from),read_rows, read_bytes, peak_memory_usage,  error, exception from system.part_log where table like '%T1%' and event_type = 2 order by event_time desc limit 1 format JSONEachRow

返回的错误详情如下:

{"query_id":"","event_type":"MergeParts","merge_reason":"RegularMerge","merge_algorithm":"Horizontal","duration_ms":"20811","partition_id":"all","part_type":"Unknown","length(merged_from)":"3100","read_rows":"244214","read_bytes":"147272968","peak_memory_usage":"3033714012","error":241,"exception":"Code: 241. DB::Exception: Memory limit (total) exceeded: would use 7.81 GiB (attempt to allocate chunk of 4196387 bytes), maximum: 7.81 GiB. OvercommitTracker decision: Memory overcommit isn't used. Waiting time or overcommit denominator are set to zero.: (while reading column clm_agent_id): (while reading from part /usr/local/clickhouse/data/store/9da/9dadcfe1-7c14-405a-8194-9c0a2596a997/all_754218_774876_86/ from mark 0 with max_rows_to_read = 1024): While executing MergeTreeSequentialSource. (MEMORY_LIMIT_EXCEEDED) (version 22.8.21.38 (official build))"}

该问题源于执行了以下SQL语句:

optimize table T1 final

执行后触发内存超限错误,尝试取消该查询但未生效,于是重启了Clickhouse服务。重启后system.processes表中已无该Optimize查询,但后台合并仍持续失败。

需要解决的问题:如何阻止Clickhouse一次性合并所有分片,以避免内存超限错误?

解决方案

1. 紧急终止后台合并任务

直接停止表T1的所有后台合并进程,终止当前持续失败的合并尝试:

SYSTEM STOP MERGES T1

2. 临时限制合并规模

修改表的合并配置,防止后续再次触发全量合并:

ALTER TABLE T1 MODIFY SETTING 
    max_background_merges = 0,                -- 暂停后台合并任务
    merge_max_partitions_to_merge_at_once = 1,-- 限制一次仅合并1个分区
    merge_with_ttl_timeout = 0                -- 禁用TTL触发的合并

3. 分批处理小分片

待合并任务完全停止后,采用分批方式合并小分片,避免内存过载:

方式一:手动合并指定小分片

先查询需要合并的小分片名称:

SELECT name FROM system.parts WHERE table = 'T1' AND rows < 5000 AND active = 1 LIMIT 10

然后手动合并这些分片(每次选择10个以内的分片):

ALTER TABLE T1 MERGE (
    'shard_name_1', 'shard_name_2', ..., 'shard_name_10'
)

重复执行该操作,直到所有小分片合并完成。

方式二:调整参数后恢复自动合并

如果希望通过自动合并处理,先修改参数控制合并规模:

ALTER TABLE T1 MODIFY SETTING 
    merge_max_total_rows_to_merge = 1000000,  -- 单次合并的总行数上限
    merge_max_rows_to_merge_at_once = 50000,  -- 单个分片参与合并的行数上限
    max_background_merges = 1,                -- 同时运行的合并任务数
    merge_min_rows_to_merge = 1000            -- 触发合并的最小行数

然后恢复后台合并:

SYSTEM START MERGES T1

让Clickhouse自动逐步合并小分片,避免一次性占用过多内存。

4. 后续规避建议

  • 禁止直接对大表执行OPTIMIZE TABLE ... FINAL,该命令会强制合并所有分片,极易触发内存不足。
  • 根据服务器内存配置,提前调整表级或全局的合并参数,合理限制合并任务的并发数和单次合并规模。
  • 对于小分片较多的表,可设置min_rows_for_wide_part参数,让小分片使用Compact存储格式,减少合并压力。

内容的提问来源于stack exchange,提问作者Pierre Louis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:37:46