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字段。该引擎的使用,会有专门的文章进行描述。

使用VersionedCollapsingMergeTree表引擎

该引擎会根据:sign, version和主键字段来对数据进行删除(折叠)操作,从而实现数据的更新。

同样,数据的合并必须要主键相同,sign字段为1和-1时,version值相同的两条数据会被合并。而sign的值和version的值,是由数据写入端写入的。

同时,数据也必须处于同一分区时才会合并,数据最终才会被删除。

使用CollapsingMergeTree表引擎

该引擎和VersionedCollapsingMergeTree引擎相同,不过该引擎不需要version字段,而是通过sign字段的值来进行数据的合并。也就是说:sign为-1和1,主键相同的两条数据会被合并(删除)。

这样,业务侧就可以把想要折叠的数据的sign字段设置为-1和1,这样就可以把历史数据删除。

比如:我们有一条id为1数据,其sign为1。当我们想要更新该id的数据时,我们就需要写两条数据,写入一条id为1,sign=-1。再写入一条最新的数据,其sign又设置为1。此时,前两条数据就会抵消,而最终会保留最新的一条数据。

小结

本文对Clickhouse的数据更新操作进行了一个概述,对更新数据的几种方式进行了说明。这几种方式的详细步骤说明,会在新的文章中进行说明。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐