OPTIMIZE 是干什么的
OPTIMIZE TABLE 手动触发 part 合并:PARTITION 限定处理范围,FINAL 把分区内的多个 part 合并成一个,DEDUPLICATE 在支持去重的引擎上按排序键或指定列去重。它常用于批量导入之后、对账之前,或者需要立刻回收重复数据的时刻。
为什么不能滥用
合并本质是重写数据:对大分区做 FINAL 会重写该分区的全部数据,占用大量 IO 与临时磁盘空间。而且 OPTIMIZE 默认异步提交,语句返回成功只代表任务已入队,不代表合并完成。日常写入的表不需要手工合并,后台合并会自动进行,频繁手工触发只会和后台任务互相抢资源。
基本信息
| 常用形式 | OPTIMIZE TABLE t [PARTITION p] [FINAL] [DEDUPLICATE [BY cols]] |
|---|---|
| 执行方式 | 默认异步排队,不等待完成 |
| 等待完成 | 设置 mutations_sync = 1 或 2 |
| 适用时机 | 批量导入后、对账前、需要立即去重时 |
| 去重前提 | 需要 ReplacingMergeTree 一类支持去重的引擎 |
示例
示例
-- 只合并指定分区
OPTIMIZE TABLE events PARTITION '202401' FINAL;
-- 等待合并完成(按副本等待)
OPTIMIZE TABLE events FINAL SETTINGS mutations_sync = 2;
-- 指定去重键
OPTIMIZE TABLE users DEDUPLICATE BY id, ts;
-- 观察 part 数量变化,确认合并是否真的完成
SELECT count() AS parts, sum(rows) AS rows
FROM system.parts
WHERE table = 'events' AND active;典型使用场景
- 批量导入之后:把小 part 合并,改善后续查询效率
- 对账之前:先合并让查询结果稳定,避免读到重复键
- 去重取最新:按业务键与版本列去重
- 分区维护:对历史分区做一次性整理
- 排查 part 过多:确认是否需要一次性合并降低元数据开销
子句作用对照
| 子句 | 作用 | 注意 |
|---|---|---|
| PARTITION p | 只处理指定分区 | 不写则处理整表 |
| FINAL | 把分区合并到单个 part | 数据量大时 IO 与磁盘占用很高 |
| DEDUPLICATE | 按排序键去重 | 只对支持去重的引擎有效 |
| BY c1, c2 | 指定去重列 | 列需要能参与比较与排序 |
| mutations_sync | 等待合并完成 | 设为 2 时按副本等待,耗时更长 |
判断合并是否真的完成,要看 system.parts 里该分区 active part 的数量变化,而不是只看语句的返回值。
对大表执行 FINAL 会重写全部分区数据,必须在低峰执行并预留足够临时磁盘空间,空间不足时任务会失败并影响同时进行的写入。