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

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 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系列文章

相关文章
|
2天前
|
机器学习/深度学习 安全 大数据
揭秘!企业级大模型如何安全高效私有化部署?全面解析最佳实践,助你打造智能业务新引擎!
【10月更文挑战第24天】本文详细探讨了企业级大模型私有化部署的最佳实践,涵盖数据隐私与安全、定制化配置、部署流程、性能优化及安全措施。通过私有化部署,企业能够完全控制数据,确保敏感信息的安全,同时根据自身需求进行优化,提升计算性能和处理效率。示例代码展示了如何利用Python和TensorFlow进行文本分类任务的模型训练。
19 6
|
17天前
|
存储 缓存 数据处理
深度解析:Hologres分布式存储引擎设计原理及其优化策略
【10月更文挑战第9天】在大数据时代,数据的规模和复杂性不断增加,这对数据库系统提出了更高的要求。传统的单机数据库难以应对海量数据处理的需求,而分布式数据库通过水平扩展提供了更好的解决方案。阿里云推出的Hologres是一个实时交互式分析服务,它结合了OLAP(在线分析处理)与OLTP(在线事务处理)的优势,能够在大规模数据集上提供低延迟的数据查询能力。本文将深入探讨Hologres分布式存储引擎的设计原理,并介绍一些关键的优化策略。
62 0
|
3月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
144 6
|
3月前
|
图形学 机器学习/深度学习 人工智能
颠覆传统游戏开发,解锁未来娱乐新纪元:深度解析如何运用Unity引擎结合机器学习技术,打造具备自我进化能力的智能游戏角色,彻底改变你的游戏体验——从基础设置到高级应用全面指南
【8月更文挑战第31天】本文探讨了如何在Unity中利用机器学习增强游戏智能。作为领先的游戏开发引擎,Unity通过ML-Agents Toolkit等工具支持AI代理的强化学习训练,使游戏角色能自主学习完成任务。文章提供了一个迷宫游戏示例及其C#脚本,展示了环境观察、动作响应及奖励机制的设计,并介绍了如何设置训练流程。此外,还提到了Unity与其他机器学习框架(如TensorFlow和PyTorch)的集成,以实现更复杂的游戏玩法。通过这些技术,游戏的智能化程度得以显著提升,为玩家带来更丰富的体验。
57 1
|
3月前
|
缓存 运维 监控
打造稳定高效的数据引擎:数据库服务器运维最佳实践全解析
打造稳定高效的数据引擎:数据库服务器运维最佳实践全解析
|
3月前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
102 0
|
4月前
|
JavaScript
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
js 解析和操作树 —— 获取树的深度、提取并统计树的所有的节点和叶子节点、添加节点、修改节点、删除节点
113 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)获取更多教程,包括系列文章覆盖的各种表引擎解析。
145 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)有更多
231 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`。有关更多信息,参见相关文章系列。
130 0