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
相关产品推荐
相关产品推荐

