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

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─┐
│ 4324182021466249494 │         5 │      146 │    1 │
└─────────────────────┴───────────┴──────────┴──────┘

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

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

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

第二行包含当前状态。

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

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

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

对于使用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─┐
│ 4324182021466249494 │         5 │      146 │    1 │       1 |
│ 4324182021466249494 │         5 │      146 │   -1 │       1 |
│ 4324182021466249494 │         6 │      185 │    1 │       2 |
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

创建表:

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─┐
│ 4324182021466249494 │         5 │      146 │    1 │       1 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘
┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │         5 │      146 │   -1 │       1 │
│ 4324182021466249494 │         6 │      185 │    1 │       2 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

我们在这里看到了什么,折叠的合并部分在哪里?我们使用两个创建了两个数据部分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─┐
│ 4324182021466249494 │         6 │      185 │       2 │
└─────────────────────┴───────────┴──────────┴─────────┘

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

SELECT * FROM UAct FINAL

┌──────────────UserID─┬─PageViews─┬─Duration─┬─Sign─┬─Version─┐
│ 4324182021466249494 │         6 │      185 │    1 │       2 │
└─────────────────────┴───────────┴──────────┴──────┴─────────┘

资料分享

ClickHouse经典中文文档分享

参考文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容