虽然在OLAP用例中很少见,但有时修改数据是不可避免的。为了满足这一需求,云数据库ClickHouse提供了Mutation功能,允许用户通过ALTER修改已插入的数据,本文为您介绍Mutation功能、使用时的注意事项以及可能产生的影响。
了解Mutation
功能介绍
定义:通过
ALTER TABLE
语句(如DELETE
、UPDATE
或ALTER COLUMN
)修改已插入的数据。实现原理:
重写数据块:Mutation 需扫描并重写所有相关
data part
,生成新data part
替换旧data part
。共享资源:与数据合并(Merge)共用线程池,可能导致两者互相抢占资源。
以下为Mutation的原理流程图。
默认行为:
全副本生效:由于分布式表的同步机制要求,Mutation需在所有副本上执行,这会显著加重集群资源负担。
适用场景:必须修改历史数据的极端场景(如修复错误或删除敏感信息)。
注意事项
Mutation操作影响较多,建议严格限制并仅由管理员执行。
影响
CPU/IO 饱和:大规模Mutation会消耗大量计算和磁盘资源,拖慢其他任务(如查询、合并)。
分布式压力:在副本节点上并行执行时,可能导致集群整体性能下降。
合并堆积:Mutation占用合并线程池,导致正常合并任务积压,引发
Too many parts
错误。复制延迟:分布式表的副本需同步Mutation,可能因节点性能不足导致数据不一致。
无法回滚:Mutation执行后即使取消,已处理的
data part
已被修改。内存资源压力:大规模Mutation也会消耗大量内存资源,导致查询因为内存使用超限被取消。
使用场景及替代方案
场景一:数据去重
当您有重复的数据需要执行合并时,建议您在插入到ClickHouse之前的上游解决这个问题。Mutation可用于数据去重,基于这种场景,可采用以下替代方案。
在查询时去重。
在查询时去重可以通过对唯一字段的行进行group by,并使用argMax函数和日期字段来确定其他字段的最新值。
使用ReplacingMergeTree去重。
ReplacingMergeTree允许具有相同排序键(ORDER BY键)的行在合并时去重。此操作只是尽可能地去重,但并不能保证完全去重。这是由于执行合并的线程在不同时间执行所导致的,因此
data part
的合并时间也无法确定,从而无法保证没有重复数据的出现。重要该功能仅适用于MergeTree系列引擎。更多详情,请参见ReplacingMergeTree。
使用FINAL去重。
您还可以使用FINAL修饰符在SELECT时强制合并
data part
,进而达到去重目的。重要此操作是资源密集型的,您需谨慎使用。
OPTIMIZE FINAL在磁盘上强制合并。
重要OPTIMIZE FINAL强制将表的所有
data part
合并成一个单一的data part
,执行时会消耗大量系统资源。
场景二:删除数据
在需要删除数据的情况下,Mutation也可用于删除数据。建议您使用lightweight deletes代替Mutation。在大多数情况下,它比使用Mutation效率更高,除非您正在进行大规模批量删除数据。
如果您的集群版本大于等于23.8,lightweight deletes功能默认已启用,其参数为enable_lightweight_delete,您无需手动开启。
如果您的集群版本小于23.8,您需手动开启lightweight deletes功能,即设置
SET allow_experimental_lightweight_delete = true;
。
lightweight deletes核心工作机制是标记删除而非立即删除。即执行DELETE
语句时,符合条件的行会被标记为删除,这些标记在查询时用于过滤行,并在parts合并时被删除。大致流程如下图所示。