Clickhouse实战–数据更新和删除概述
说明
在Clickhouse中可以有多种方法来更新数据,不同方法适用的场景不同。总的来说,在CK中更新数据方法有以下几种:
(1)直接使用update语句
(2)先删除数据,再插入最新的数据
(3)ReplacingMergeTree表引擎+Insert语句
(4)CollapsingMergeTree表引擎+Insert语句
(5)VersionedCollapsingMergeTree表引擎+Insert语句
Update和Delete操作
ClickHouse提供了DELETE和UPDATE的能力,这类操作被称为Mutation操作,它可以看作ALTER语句的变种。
虽然Mutation能最终实现修改和删除,但不能完全以通常意义上的UPDATE和DELETE来理解,我们必须清醒地认识到它的不同,主要有以下几个方面:
- Mutation语句是一种“很重”的操作,更适用于批量数据的修改和删除;
- 它不支持事务,一旦语句被提交执行,就会立刻对现有数据产生影响,无法回滚;
- Mutation语句的执行是一个异步的后台过程,语句被提交之后就会立即返回,但这并不代表具体逻辑已经执行完毕,它的具体执行进度需要通过system.mutations系统表查询。
- 对于*MergeTree表引擎,在执行Mutation操作时是通过重写整个分区数据来实现的(使用新的分区代替老的分区)。如果需要操作的分区非常多,optimize的耗时会非常长甚至失败。此时,可以根据实际情况和分区的分布使数据的更新只涉及部分分区来提高效率。
- 对于update操作:不能更新是主键的列(在primary by或order by中的列),
- 对于delete操作:可以使用ALTER DELETE来灵活删除旧数据。对于定期删除操作,主要缺点是:需要有一个外部系统来提交操作命令。性能方面的考虑,因为即使只有一行要删除,Mutation操作也会重写完整的分区。
使用ReplacingMergeTree表引擎
在创建该引擎的数据表时一般会创建一个ver字段,该引擎在后台合并分区数据时会删除:主键(order by 后面的列)相同,而ver较小的数据行,只会保留一条ver最大的那一条数据。若没有指定ver字段,会保留主键相同,最新的一条数据。这样,就间接的通过insert操作实现了数据的删除、更新。
要注意的是,Clickhouse后台的数据合并操作不是立即执行的,而是要等到分区数据合并时才会执行,而后台数据合并的时间是不确定的,业务实现时不能依赖这个时间。
那么,若我们想要让数据替换操作立即生效,该怎么办呢?Clickhouse也提供了一个选择,那就是在查询语句时添加final关键字。添加final关键字后,会根据规则自动去重数据,但可能对查询的性能有一定影响。
另外,还需要注意,必须是同一个分区的数据才会被合并。也就是说,要想对相同主键的数据去重,必须保证这些数据处于同一个分区;那么,若是分布式表,首先要保证数据落到同一个节点上。
该引擎的建表语句如下:
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = ReplacingMergeTree([ver])
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]
从建表语句可以看到,在创建表时ReplacingMergeTree的引擎中,必须指定ver字段。该引擎的使用,会有专门的文章进行描述。