ReplacingMergeTree:实现 Clickhouse 数据更新
摘要:Clickhouse 作为一个 OLAP 数据库,它对事务的支持非常有限。本文主要介绍通过 ReplacingMergeTree 来实现 Clickhouse 数据的更新、删除。
本文分享自华为云社区《Clickhouse如何实现数据更新》,作者: 小霸王。
Clickhouse 作为一个 OLAP 数据库,它对事务的支持非常有限。Clickhouse 提供了 MUTATION 操作(通过 ALTER TABLE 语句)来实现数据的更新、删除,但这是一种“较重”的操作,它与标准 SQL 语法中的 UPDATE、DELETE 不同,是异步执行的,对于批量数据不频繁的更新或删除比较有用,可参考https://altinity.com/blog/2018/10/16/updates-in-clickhouse。除了 MUTATION 操作,Clickhouse 还可以通过 CollapsingMergeTree、VersionedCollapsingMergeTree、ReplacingMergeTree 结合具体业务数据结构来实现数据的更新、删除,这三种方式都通过 INSERT 语句插入最新的数据,新数据会“抵消”或“替换”掉老数据,但是“抵消”或“替换”都是发生在数据文件后台 Merge 时,也就是说,在 Merge 之前,新数据和老数据会同时存在。因此,我们需要在查询时做一些处理,避免查询到老数据。Clickhouse 官方文档提供了使用 CollapsingMergeTree、VersionedCollapsingMergeTree 的指导,https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/collapsingmergetree/。相比于 CollapsingMergeTree、VersionedCollapsingMergeTree 需要标记位字段、版本字段,用 ReplacingMergeTree 来实现数据的更新删除会更加方便,这里着重介绍一下如何用 ReplacingMergeTree 来实现数据的更新删除。
我们假设一个需要频繁数据更新的场景,如某市用户用电量的统计,我们知道,用户的用电量每分每秒都有可能发生变化,所以会涉及到数据频繁的更新。首先,创建一张表来记录某市所有用户的用电量。
PowerConsumption_local 为本地表,PowerConsumption 为对应的分布式表。其中 PowerConsumption_local 使用 ReplicatedReplacingMergeTree 表引擎,第三个参数‘Record_Time’表示相同主键的多条数据,只会保留 Record_Time 最大的一条,我们正是利用 ReplacingMergeTree 的这一特性来实现数据的更新删除。因此,在选择主键时,我们需要确保主键唯一。这里我们选择(User_ID, Address)来作为主键,因为用户 ID 加上用户的地址可以确定唯一的一个电表,不会出现第二个相同的电表,所以对于某个电表多条数据,只会保留电量记录时间最新的一条。
然后我们向表中插入 10 条数据:
表中数据如图所示:
假如现在我们要行政区编码为 1 的所有用户数据都需要更新,我们插入最新的数据:
插入最新数据后,表中数据如图所示:
可以看到,此时新插入的数据与老数据同时存在于表中,因为后台数据文件还没有进行 Merge,“替换”还没有发生,这时就需要对查询语句做一些处理来过滤掉老数据,函数 argMax(a, b)可以按照 b 的最大值取 a 的值,所以通过如下查询语句就可以只获取到最新数据:
查询结果如下图:
为了更方便我们查询,这里可以创建一个视图:
通过该视图,可以查询到最新的数据:
假如现在我们又需要删除用户 ID 为 0 的数据,我们需要插入一条 User_ID 字段为 0,Deleted 字段为 1 的数据:
查询视图,发现 User_ID 为 0 的数据已经查询不到了:
通过如上方法,我们可以实现 Clickhouse 数据的更新、删除,就好像在使用 OLTP 数据库一样,但我们应该清楚,实际上老数据真正的删除是在数据文件 Merge 时发生的,只有在 Merge 后,老数据才会真正物理意义上的删除掉。
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/7ab73847b53646acd13093e3e】。文章转载请联系作者。
评论