该引擎继承于MergeTree,并在数据块合并算法中添加了折叠行的逻辑。CollapsingMergeTree会异步的删除(折叠)这些除了特定列Sign有1和-1的值以外,其余所有字段的值都相等的成对的行。没有成对的行会被保留。因此,该引擎可以显著的降低存储量并提高SELECT查询效率。

简单来说就是,clickhouse会自动的合并有效和无效的数据,减少数据存储,并减少update所产生的性能消耗。具体的逻辑,下面介绍。

建表

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

sign — 类型列的名称:1是«状态»行,也就是最后的有效行,-1是«取消»行,也就是无效行。列数据类型 — Int8。

创建CollapsingMergeTree表时,需要与创建 MergeTree 表时相同的子句。

折叠

数据

考虑你需要为某个对象保存不断变化的数据的情景。似乎为一个对象保存一行记录并在其发生任何变化时更新记录是合乎逻辑的,但是更新操作对DBMS来说是昂贵且缓慢的,因为它需要重写存储中的数据。如果你需要快速的写入数据,则更新操作是不可接受的,但是你可以按下面的描述顺序地更新一个对象的变化。

在写入行的时候使用特定的列Sign。如果Sign=1则表示这一行是对象的状态,我们称之为«状态»行。如果Sign=-1则表示是对具有相同属性的状态行的取消,我们称之为«取消»行。

例如,我们想要计算用户在某个站点访问的页面页面数以及他们在那里停留的时间。在某个时候,我们将用户的活动状态写入下面这样的行。

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┘

一段时间后,我们写入下面的两行来记录用户活动的变化。

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 5 │ 146 │ -1 │
│ 4324182021466249494 │ 6 │ 185 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┘

第一行取消了这个对象(用户)的状态。它需要复制被取消的状态行的所有除了Sign的属性。

第二行包含了当前的状态。因为我们只需要用户活动的最后状态,这些行可以在折叠对象的失效(老的)状态的时候被删除。CollapsingMergeTree会在合并数据片段的时候做这件事。

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │
│ 4324182021466249494 │ 5 │ 146 │ -1 │
└─────────────────────┴───────────┴──────────┴──────┘

这种方法的特殊属性

  1. 写入的程序应该记住对象的状态从而可以取消它。«取消»字符串应该是«状态»字符串的复制,除了相反的Sign。它增加了存储的初始数据的大小,但使得写入数据更快速。
  2. 由于写入的负载,列中长的增长阵列会降低引擎的效率。数据越简单,效率越高。
  3. SELECT的结果很大程度取决于对象变更历史的一致性。在准备插入数据时要准确。在不一致的数据中会得到不可预料的结果,例如,像会话深度这种非负指标的负值。

算法

当ClickHouse合并数据片段时,每组具有相同主键的连续行被减少到不超过两行,一行Sign=1(«状态»行),另一行Sign=-1(«取消»行),换句话说,数据项被折叠了。

对每个结果的数据部分ClickHouse保存的算法

  1. 如果«取消»和«状态»行数量相同,并且最后一行«状态»行,保留第一个«取消»和最后一个«状态»行。
  2. 如果«状态»行比«取消»行多一个或一个以上,保留最后一个«状态»行。
  3. 如果«取消»行比«状态»行多一个或一个以上,保留第一个«取消»行。
  4. 没有行,在其他所有情况下。合并会继续,但ClickHouse会把此情况视为逻辑错误并将其记录在服务日志中。这个错误会在相同的数据被插入超过一次时出现。

因此,折叠不应该改变统计数据的结果。变化逐渐地被折叠,因此最终几乎每个对象都只剩下了最后的状态。

Sign是必须的因为合并算法不保证所有有相同主键的行都会在同一个结果数据片段中,甚至是在同一台物理服务器上。ClickHouse用多线程来处理SELECT请求,所以它不能预测结果中行的顺序。如果要从CollapsingMergeTree表中获取完全«折叠»后的数据,则需要聚合。

要完成折叠,请使用GROUP BY子句和用于处理符号的聚合函数编写请求。例如,要计算数量,使用sum(Sign)而不是 count()。要计算某物的总和,使用sum(Sign * x)而不是sum(x),并添加HAVING sum(Sign) > 0子句。

聚合体count,sum和avg可以用这种方式计算。如果一个对象至少有一个未被折叠的状态,则可以计算uniq聚合。min和 max聚合无法计算,因为CollaspingMergeTree不会保存折叠状态的值的历史记录。

如果你需要在不进行聚合的情况下获取数据(例如,要检查是否存在最新值与特定条件匹配的行),你可以在 FROM 从句中使用 FINAL 修饰符。这种方法显然是更低效的。

# 示例:

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │
│ 4324182021466249494 │ 5 │ 146 │ -1 │
│ 4324182021466249494 │ 6 │ 185 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┘ # 建表: CREATE TABLE UAct
(
UserID UInt64,
PageViews UInt8,
Duration UInt8,
Sign Int8
)
ENGINE = CollapsingMergeTree(Sign)
ORDER BY UserID # 插入数据: INSERT INTO UAct VALUES (4324182021466249494, 5, 146, 1) INSERT INTO UAct VALUES (4324182021466249494, 5, 146, -1),(4324182021466249494, 6, 185, 1) #我们使用两次INSERT请求来创建两个不同的数据片段。如果我们使用一个请求插入数据,ClickHouse只会创建一个数据片段且不会执行任何合并操作。 #获取数据: SELECT * FROM UAct ┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 5 │ 146 │ -1 │
│ 4324182021466249494 │ 6 │ 185 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 5 │ 146 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┘ #我们看到了什么,哪里有折叠? #通过两个 INSERT 请求,我们创建了两个数据片段。
#SELECT请求在两个线程中被执行,我们得到了随机顺序的行。
#没有发生折叠是因为还没有合并数据片段。
#ClickHouse 在一个我们无法预料的未知时刻合并数据片段。 #因此我们需要聚合: SELECT
UserID,
sum(PageViews * Sign) AS PageViews,
sum(Duration * Sign) AS Duration
FROM UAct
GROUP BY UserID
HAVING sum(Sign) > 0 ┌──────────────UserID─┬─PageViews─┬─Duration─┐
│ 4324182021466249494 │ 6 │ 185 │
└─────────────────────┴───────────┴──────────┘ # 如果我们不需要聚合并想要强制进行折叠,我们可以在 FROM 从句中使用 FINAL 修饰语。 SELECT * FROM UAct FINAL ┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┐
│ 4324182021466249494 │ 6 │ 185 │ 1 │
└─────────────────────┴───────────┴──────────┴──────┘ # 这种查询数据的方法是非常低效的。不要在大表中使用它。

资料分享

ClickHouse经典中文文档分享

参考文章

ClickHouse(13)ClickHouse合并树MergeTree家族表引擎之CollapsingMergeTree详细解析的更多相关文章

  1. ClickHouse(10)ClickHouse合并树MergeTree家族表引擎之ReplacingMergeTree详细解析

    目录 建表语法 数据处理策略 资料分享 参考文章 MergeTree拥有主键,但是它的主键却没有唯一键的约束.这意味着即便多行数据的主键相同,它们还是能够被正常写入.在某些使用场合,用户并不希望数据表 ...

  2. ClickHouse(11)ClickHouse合并树MergeTree家族表引擎之SummingMergeTree详细解析

    目录 建表语法 数据处理 汇总的通用规则 AggregateFunction 列中的汇总 嵌套结构数据的处理 资料分享 参考文章 SummingMergeTree引擎继承自MergeTree.区别在于 ...

  3. ClickHouse(12)ClickHouse合并树MergeTree家族表引擎之AggregatingMergeTree详细解析

    目录 建表语法 查询和插入数据 数据处理逻辑 ClickHouse相关资料分享 AggregatingMergeTree引擎继承自 MergeTree,并改变了数据片段的合并逻辑.ClickHouse ...

  4. Clickhouse表引擎之MergeTree

    1.概述 在Clickhouse中有多种表引擎,不同的表引擎拥有不同的功能,它直接决定了数据如何读写.是否能够并发读写.是否支持索引.数据是否可备份等等.本篇博客笔者将为大家介绍Clickhouse中 ...

  5. UniqueMergeTree:支持实时更新删除的 ClickHouse 表引擎

    UniqueMergeTree 开发的业务背景 首先,我们看一下哪些场景需要用到实时更新. 我们总结了三类场景: 第一类是业务需要对它的交易类数据进行实时分析,需要把数据流同步到 ClickHouse ...

  6. Clickhouse表引擎探究-ReplacingMergeTree

    作者:耿宏宇 1 表引擎简述 1.1 官方描述 MergeTree 系列的引擎被设计用于插入极大量的数据到一张表当中.数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合 ...

  7. ClickHouse入门:表引擎-HDFS

    前言插件及服务器版本服务器:ubuntu 16.04Hadoop:2.6ClickHouse:20.9.3.45 文章目录 简介 引擎配置 HDFS表引擎的两种使用形式 引用 简介 ClickHous ...

  8. ClickHouse(02)ClickHouse架构设计介绍概述与ClickHouse数据分片设计

    ClickHouse核心架构设计是怎么样的?ClickHouse核心架构模块分为两个部分:ClickHouse执行过程架构和ClickHouse数据存储架构,下面分别详细介绍. ClickHouse执 ...

  9. 【大数据面试】ClickHouse:介绍、特点、数据类型、引擎、操作、副本、分片

    1.介绍 开源的列式存储数据库(DBMS),由C++编写,用于在线分析处理查询(OLAP) 可以通过SQL查询实时生成分析数据报告 解释: DBMS:数据库管理系统 常见的列式存储数据库:Hbase. ...

  10. EXCEL 如何将多个工作表或工作簿合并到一个工作表

    在使用Excel 时,我们经常需要将多个工作表或工作簿合并到一个工作表中,这样我们就能快速地对数据进行分析和统计.对于一般用户而言,除了复制每个工作表后再粘贴,没有其他什么方法了.如果只是合并少数几个 ...

随机推荐

  1. vue设计与实现 第6章 ref 响应原理 笔记

    ref 函数实现代码 const a = ref(1); function ref(value){ const wrapper = {value} Object.defineProperty(wrap ...

  2. JavaScript入门⑧-事件总结大全

    JavaScript入门系列目录 JavaScript入门①-基础知识筑基 JavaScript入门②-函数(1)基础{浅出} JavaScript入门③-函数(2)原理{深入}执行上下文 JavaS ...

  3. MySQL事务(四大特性)-存储过程

    目录 一:事务 1.四大特性(ACID) 2.事物存在的必要性(真实比喻) 3.如何使用事务 4.开启事务-回滚-确认 二:事务案例实战 1.模拟消费 2.创建 3.插入数据 4.开启事务 5.修改操 ...

  4. loadrunner11安装时提示缺少Microsoft Visual c++2005 sp1组件的解决办法

    解决方法: 1.进入loadrunner-11安装程序\loadrunner-11\Additional Components\IDE Add-Ins\MS Visual Studio .NET文件夹 ...

  5. vue下载与安装

    首先安装node.js环境: node.js 安装推荐文章:https://www.cnblogs.com/zhouyu2017/p/6485265.html 基于node.js安装淘宝镜像npm i ...

  6. 如何在路由绑定中使用 IParsable

    IParsable 是 .Net 7 中新增的接口,它可以将字符串转换为对应的实体.在 Controller 的 Route 绑定中可以使用 IParsable 来绑定复杂的实体. 实验背景 假设有一 ...

  7. [OpenCV实战]28 基于OpenCV的GUI库cvui

    目录 1 cvui的使用 1.1 如何在您的应用程序中添加cvui 1.2 基本的"hello world"应用程序 2 更高级的应用 3 代码 4 参考 有很多很棒的GUI库,例 ...

  8. curl请求https报错

    curl 一般情况下请求http时不会有问题 但是请求 https 协议的链接时会报错,如下: curl: (60) SSL certificate problem: unable to get lo ...

  9. [数据结构]Hash Table(哈希表)

    Hash Table基本概念 散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr. 散列函数可能会把两个或者两个以上的关键字映射到同一个地址,称这种情况为 ...

  10. 解决 requests cookies 为空的坑

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/5d14f0d7.html 你好,我是测试蔡坨坨. 我们在做接口自动化测试的时候,一般会通过调用登录接口来获取cookies. ...