ClickHouse(14)ClickHouse合并树MergeTree家族表引擎之VersionedCollapsingMergeTree详细解析

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: VersionedCollapsingMergeTree是ClickHouse的一种优化引擎,扩展了MergeTree,支持多线程异步插入和高效的数据折叠。它通过Sign和Version列处理对象状态的变化,Sign表示行的状态(正向或撤销),Version追踪状态版本。引擎自动删除旧状态,减少存储占用。在查询时,需注意可能需使用GROUP BY和聚合函数确保数据折叠,因为ClickHouse不保证查询结果已折叠。文章还提供了建表语法、使用示例和相关资源链接。

VersionedCollapsingMergeTree引擎继承自MergeTree并将折叠行的逻辑添加到合并数据部分的算法中。VersionedCollapsingMergeTree用于相同的目的折叠树但使用不同的折叠算法,允许以多个线程的任何顺序插入数据。特别是,Version列有助于正确折叠行,即使它们以错误的顺序插入。相比之下,CollapsingMergeTree只允许严格连续插入。

VersionedCollapsingMergeTree引擎的作用如下:

  • 允许快速写入不断变化的对象状态。
  • 删除后台中的旧对象状态。 这显著降低了存储体积。

建表语法

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = VersionedCollapsingMergeTree(sign, version)
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]

针对于VersionedCollapsingMergeTree(sign, version)两个特殊的参数。

sign — 指定行类型的列名:1是一个“state”行,-1是一个“cancel”行列数据类型应为Int8.
version — 指定对象状态版本的列名。列数据类型应为UInt*.

使用场景

考虑一种情况,您需要为某个对象保存不断变化的数据。对于一个对象有一行,并在发生更改时更新该行是合理的。但是,对于数据库管理系统来说,更新操作非常昂贵且速度很慢,因为它需要重写存储中的数据。如果需要快速写入数据,则不能接受更新,但可以按如下顺序将更改写入对象。使用 Sign 列写入行时。如果Sign=1这意味着该行是一个对象的状态(让我们把它称为“state”行)。如果Sign=-1它指示具有相同属性的对象的状态的取消(让我们称之为“cancel”行)。 还可以使用 Version 列,它应该用单独的数字标识对象的每个状态。

例如,我们要计算用户在某个网站上访问了多少页面以及他们在那里的时间。在某个时间点,我们用用户活动的状态写下面的行:

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 432418202146624949451461 │
└─────────────────────┴───────────┴──────────┴──────┘

在稍后的某个时候,我们注册用户活动的变化,并用以下两行写入它。

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 43241820214662494945146-1 │
│ 432418202146624949461851 │
└─────────────────────┴───────────┴──────────┴──────┘

第一行取消对象(用户)的先前状态。它应该复制已取消状态的所有字段,除了Sign。

第二行包含当前状态。

因为我们只需要用户活动的最后一个状态,所以需要删除,折叠对象的无效(旧)状态。VersionedCollapsingMergeTree会在在合并数据部分时执行此操作。

最终折叠之后的结果如下。

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494514611 |43241820214662494945146-11 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

对于使用VersionedCollapsingMergeTree有下面三个需要注意的点。

  1. 写入数据的程序应该记住对象的状态以取消它。该“cancel”字符串应该是“state”与相反的字符串Sign。这增加了存储的初始大小,但允许快速写入数据。
  2. 列中长时间增长的数组由于写入负载而降低了引擎的效率。数据越简单,效率就越高。
  3. SELECT结果很大程度上取决于对象变化历史的一致性。准备插入数据时要准确。不一致的数据将导致不可预测的结果,例如会话深度等非负指标的负值。

合并算法

合并算法主要是下面两个。

  • 当ClickHouse合并数据部分时,它会删除具有相同主键和版本但Sign值不同的一对行.行的顺序并不重要。
  • 当ClickHouse插入数据时,它会按主键对行进行排序。如果Version列不在主键中,ClickHouse将其隐式添加到主键作为最后一个字段并使用它进行排序。

ClickHouse不保证具有相同主键的所有行都将位于相同的结果数据部分中,甚至位于相同的物理服务器上。对于写入数据和随后合并数据部分都是如此。此外,ClickHouse流程SELECT具有多个线程的查询,并且无法预测结果中的行顺序。这意味着,如果有必要从VersionedCollapsingMergeTree表中得到完全“collapsed”的数据,聚合是必需的。

也就是说ClickHouse并不保证查询出来的数据一定是经过合并折叠的。如果要保证一定经过折叠合并,需要查询的时候使用GROUP BY和聚合函数。

要计算数量,使用sum(Sign)而不是count()。要计算的东西的总和,使用sum(Sign * x)而不是sum(x),并添加HAVING sum(Sign) > 0。可以在一定程度上避免数据未折叠导致的数据问题。

如果您需要手动折叠合并,但是,如果没有聚合(例如,要检查是否存在其最新值与某些条件匹配的行),则可以使用FINAL修饰FROM条件这种方法效率低下,不应与大型表一起使用。

使用例子、

示例数据:

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494514611 |43241820214662494945146-11 |4324182021466249494618512 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

创建表:

CREATE TABLE UAct
(
    UserID UInt64,
    PageViews UInt8,
    Duration UInt8,
    Sign Int8,
    Version UInt8
)
ENGINE = VersionedCollapsingMergeTree(Sign, Version)
ORDER BY UserID

插入数据:


INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1, 1)

INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1, 1),(4324182021466249494, 6, 185, 1, 2)

我们用两个INSERT查询以创建两个不同的数据部分。
如果我们使用单个查询插入数据,ClickHouse将创建一个数据部分,并且永远不会执行任何合并。

获取数据:

SELECT * FROM UAct

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494514611 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 43241820214662494945146-11 │
│ 4324182021466249494618512 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

我们在这里看到了什么,折叠的合并部分在哪里?我们使用两个创建了两个数据部分INSERT查询。该SELECT查询是在两个线程中执行的,结果是行的随机顺序。由于数据部分尚未合并,因此未发生折叠合并。 ClickHouse在我们无法预测的未知时间点合并数据部分。

这就是为什么我们需要聚合:

SELECT
    UserID,
    sum(PageViews * Sign) AS PageViews,
    sum(Duration * Sign) AS Duration,
    Version
FROM UAct
GROUP BY UserID, Version
HAVING sum(Sign) > 0

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Version─┐
│ 432418202146624949461852 │
└─────────────────────┴───────────┴──────────┴─────────┘

如果我们不需要聚合,并希望强制折叠,我们可以使用 FINAL 修饰符 FROM 条款

SELECT * FROM UAct FINAL

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494618512 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

资料分享

ClickHouse经典中文文档分享

clickhouse系列文章

相关文章
|
1月前
|
消息中间件 分布式计算 关系型数据库
大数据-140 - ClickHouse 集群 表引擎详解5 - MergeTree CollapsingMergeTree 与其他数据源 HDFS MySQL
大数据-140 - ClickHouse 集群 表引擎详解5 - MergeTree CollapsingMergeTree 与其他数据源 HDFS MySQL
46 0
|
1月前
|
SQL 消息中间件 分布式计算
大数据-141 - ClickHouse 集群 副本和分片 Zk 的配置 Replicated MergeTree原理详解(一)
大数据-141 - ClickHouse 集群 副本和分片 Zk 的配置 Replicated MergeTree原理详解(一)
56 0
|
1月前
|
SQL 大数据
大数据-141 - ClickHouse 集群 副本和分片 Zk 的配置 Replicated MergeTree原理详解(二)
大数据-141 - ClickHouse 集群 副本和分片 Zk 的配置 Replicated MergeTree原理详解(二)
65 0
|
1月前
|
存储 SQL 分布式计算
大数据-139 - ClickHouse 集群 表引擎详解4 - MergeTree 实测案例 ReplacingMergeTree SummingMergeTree
大数据-139 - ClickHouse 集群 表引擎详解4 - MergeTree 实测案例 ReplacingMergeTree SummingMergeTree
31 0
|
1月前
|
存储 算法 NoSQL
大数据-138 - ClickHouse 集群 表引擎详解3 - MergeTree 存储结构 数据标记 分区 索引 标记 压缩协同
大数据-138 - ClickHouse 集群 表引擎详解3 - MergeTree 存储结构 数据标记 分区 索引 标记 压缩协同
34 0
|
1月前
|
存储 消息中间件 分布式计算
大数据-137 - ClickHouse 集群 表引擎详解2 - MergeTree 存储结构 一级索引 跳数索引
大数据-137 - ClickHouse 集群 表引擎详解2 - MergeTree 存储结构 一级索引 跳数索引
32 0
|
4月前
|
JavaScript
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
125 0
|
5月前
|
SQL NoSQL 关系型数据库
ClickHouse(24)ClickHouse集成mongodb表引擎详细解析
**MongoDB引擎在ClickHouse中提供只读访问远程数据,用于`SELECT`查询。不支持写入。创建MongoDB表引擎的语法:`CREATE TABLE ... ENGINE = MongoDB(host, db, coll, user, pass)`。例如:**查看[ClickHouse中文文档](https://zhangfeidezhu.com/?p=468)获取更多教程,包括系列文章覆盖的各种表引擎解析。
152 0
|
5月前
|
SQL 关系型数据库 MySQL
ClickHouse(23)ClickHouse集成Mysql表引擎详细解析
ClickHouse的MySQL引擎允许执行`SELECT`查询从远程MySQL服务器。使用`MySQL('host:port', 'database', 'table', 'user', 'password'[,...])`格式连接,支持简单`WHERE`子句在MySQL端处理,复杂条件和`LIMIT`在ClickHouse端执行。不支持`NULL`值,用默认值替换。系列文章涵盖ClickHouse安装、集群搭建、表引擎解析等主题。[链接](https://zhangfeidezhu.com/?p=468)有更多
256 0
|
5月前
|
SQL 分布式计算 安全
ClickHouse(22)ClickHouse集成HDFS表引擎详细解析
ClickHouse的HDFS引擎允许直接在Hadoop生态系统内管理数据。使用`ENGINE=HDFS(URI, format)`,其中URI指定HDFS路径,format定义文件格式(如TSV、CSV或ORC)。表可读写,但不支持`ALTER`、`SELECT...SAMPLE`、索引和复制操作。通配符可用于文件路径,如`*`、`?`和范围`{N..M}`。Kerberos认证可配置。虚拟列包括文件路径 `_path` 和文件名 `_file`。有关更多信息,参见相关文章系列。
143 0

推荐镜像

更多