在前面的文章中,我们详细介绍了ClickHouse MergeTree表引擎的使用场景、原理、数据存储结构、建表语句以及索引优化。详见《ClickHouse MergeTree表引擎和建表语句》、《ClickHouse MergeTree二级索引/跳数索引》。

MergeTree引擎表是使用最为广泛的表,除了MergeTree引擎表以外,MergeTree家族还有一些特殊的表引擎,在一些特殊场景中能够表现出更好地性能。例如,统计电商平台每天的销售额等。

1. AggregatingMergeTree

作为MergeTree家族中的一员,AggregatingMergeTree 表引擎也继承自MergeTree引擎。从名字也可以看出,AggregatingMergeTree 主要是一种聚合表引擎,可以把一个数据片段内的原始数据根据主键(确切地说是排序键)按照给定的聚合函数进行增量聚合。聚合函数主要有两种类型:

(1)AggregateFunction

AggregateFunction类型聚合函数具有实现定义的中间状态,该状态可以序列化为AggregateFunction(…)数据类型,并通常通过物化视图存储在表中,类似于Tensorflow1中的静态图和Spark中的懒加载算子,只定义计算逻辑,但不执行。。

生成聚合函数状态的方法是在建表的时候定义 AggregateFunction 类型字段,插入数据的时候使用带有 State 后缀的函数写入,- State 函数返回的是状态,而不是最终值。换句话说,它们返回AggregateFunction类型的值。读取数据的时候使用带有 Merge 后缀的函数查询就可以了。例如:

建表,uniq、sum、quantiles 都是clickhouse支持的聚合函数
CREATE TABLE t
(column0 UInt16,column1 AggregateFunction(uniq, UInt64),column2 AggregateFunction(sum, Decimal32(2)),column3 AggregateFunction(quantiles(0.5, 0.9), UInt64)
) ENGINE = AggregatingMergeTree()
[PARTITION BY expr]
[ORDER BY expr]
[SAMPLE BY expr]
[TTL expr]
[SETTINGS name=value, ...]插入数据
INSERT INTO TABLE t SELECT 1, uniqState(10), sumState(toDecimal32(10000,2)), quantilesState(0.5, 0.9)(25);查询数据
SELECT uniqMerge(column1), sumMerge(column2) FROM t GROUP BY ... ;

查询数据时,需使用 GROUP BY 子句并且要使用与插入时相同的聚合函数,带有Merge后缀的聚合函数接受一组状态(State),将它们组合在一起,并返回完整数据聚合的结果。例如,以下两个查询返回相同的结果:

SELECT uniq(UserID) FROM table;
SELECT uniqMerge(state) FROM (SELECT uniqState(UserID) AS state FROM table GROUP BY RegionID);

(2)SimpleAggregateFunction

AggregateFunction 有一个有一个很大的缺点,需要存储数据的全部状态,对于sum、max等聚合操作完全可以对已有数据进行预计算,写入新的数据时,只需要把新的聚合结果和预聚合结果进行聚合更新就可以了,AggregateFunction 似乎完全体现不出 Aggregate 的优势。因此,对于这种可以预聚合的操作,clickhouse又提供了另一种数据类型——SimpleAggregateFunction。SimpleAggregateFunction的性能高于AggregateFunction,支持的聚合函数如下:

any
anyLast
min
max
sum
sumWithOverflow
groupBitAnd
groupBitOr
groupBitXor
groupArrayArray
groupUniqArrayArray
sumMap
minMap
maxMap

建表语句如下:

CREATE TABLE simple (id UInt64, val SimpleAggregateFunction(sum, Double)) ENGINE=AggregatingMergeTree ORDER BY id;

※注意: 生成SimpleAggregateFunction聚合函数值的常用方法是调用带有 SimpleState后缀的聚合函数,如 sumSimpleState。

(3)物化视图建表

可以发现上面这种形式是很麻烦的,一般情况下很少使用,更常用的方法是通过物化视图的形式创建 AggregatingMergeTree 表(关于物化视图的概念,我们后面介绍,可以参考其他数据库view理解,相当于一张虚拟表,但是与普通视图完全不同)。先建立一个 MergeTree 表,然后建立AggregatingMergeTree引擎的物化视图跟踪基础表。这样即保存了明细数据,不破坏原有数据结构,又可以跟踪聚合结果。例如:

建立基础表
CREATE TABLE test.visits
(CounterID UInt16,StartDate Date,Sign UInt8,UserID UInt32,
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(StartDate)
ORDER BY CounterID, StartDate;创建AggregatingMergeTree引擎物化视图
CREATE MATERIALIZED VIEW test.basic
ENGINE = AggregatingMergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate)
AS SELECTCounterID,StartDate,sumState(Sign)    AS Visits,uniqState(UserID) AS Users
FROM test.visits
GROUP BY CounterID, StartDate;

在新增数据时,把明细数据写入基础表 test.visits 中,在查询聚合结果时,直接查物化视图 test.basic 即可:

SELECTStartDate,sumMerge(Visits) AS Visits,uniqMerge(Users) AS Users
FROM test.basic
GROUP BY StartDate
ORDER BY StartDate;

2. SummingMergeTree

SummingMergeTree 同样继承自 MergeTree,可以认为是 AggregatingMergeTree 的一种特殊方式,同样基于主键(或者更准确地说,使用相同的排序键)聚合,在使用时也多是基于一张明细表建立物化视图,这样不会丢失原有数据,如果发现聚合键不合适,还可以修改。另外,需要注意:

  • SummingMergeTree 只能对非主键数值型字段进行聚合,如果用于汇总的所有列中的值均为0,则该行会被删除,对于不能聚合的数据类型,将随机选择一条记录。
  • SummingMergeTree 会定期合并插入的数据片段,也就是说当查询的时候可能还有数据没有进行聚合处理,而且数据是分片段合并(不跨分区sum),一个聚合键会对应多条数据,所以使用过程中一定还要使用 sum() GROUP BY 查询,SummingMergeTree 起到的是优化效果。
  • SummingMergeTree 也可处理嵌套类型数据,而且支持和 ORDER BY 字段组成复合key,查询的时候使用sumMap函数进行聚合操作。

建表语句如下:

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

SummingMergeTree中的 [columns] 表示需要聚合的列,如果没有指定,表示对主键之外的所有数值型字段进行聚合。例如:

建表
CREATE TABLE summtt
(key UInt32,value UInt32
)
ENGINE = SummingMergeTree()
ORDER BY key;插入数据
INSERT INTO summtt Values(1,1),(1,2),(2,1);查询
SELECT key, sum(value) FROM summtt GROUP BY key;

在前面介绍MergeTree表引擎的时候,我们有提到,一般情况下我们不需要单独指定主键字段,ORDER BY 字段就是主键字段。但是在 AggregatingMergeTree 和 SummingMergeTree 表中可以指定 PRIMARY KEY 和 ORDER BY 字段不同,因为如果不单独定义主键,而聚合键字段又比较多,就会导致主键过多,降低写效率,而且可能需要增加新的聚合维度,泛化能力降低。此时就可以只保留少量的列在主键当中用于提升扫描效率,将其余的维度列添加到排序键元组中。

例如:假设有一张表有col1,col2,col3,col4四个字段,我们需要按照col1,col2进行聚合,并经常需要通过col1字段过滤,则可以按照如下定义:

PRIMARY KEY col1
ORDER BY  (col1,col2)

3. ReplacingMergeTree

ReplacingMergeTree 引擎表会在后台合并时对 ORDER BY 字段相同的行进行去重。建表语句如下:

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

※ 注意:

  • ReplacingMergeTree 表是按照 ORDER BY 字段去重,不是 PRIMARY KEY 字段。
  • ReplacingMergeTree 是在Merge的时候才会进行去重,所以不是绝对保证的。因此,ReplacingMergeTree 适用于在后台清除重复数据以节省空间,但不能保证没有重复。
  • [ver] 是版本号字段参数,可以是 UInt*, Date, DateTime, DateTime64 类型。在Merge的时候会保留 版本号最大的那条记录,如果没有指定 [ver],则保留最新的(最后写入的)记录。
  • 合并去重是按照分区去重的,不会跨分区去重。

4. CollapsingMergeTree

CollapsingMergeTree 同样继承自 MergeTree 表引擎,主要用来删除数据。我们知道MergeTree 表改、删的效率是比较低的,CollapsingMergeTree 引擎采用了 “以增代删” 的思想。建表语句如下:

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, ...]

CollapsingMergeTree 引擎表有一个 sign 参数,sign 是一个类型为 Int8 的字段名,可以取值 1 和 -1。1 表示正常插入的数据,-1表示删除上一条 sign = 1的记录,所以 CollapsingMergeTree 删除数据是通过插入一条新记录实现,这也是 Collapsing (折叠)的含义所在。对于同一个分区内(不能跨分区)ORDER BY 字段相同的记录,如果两条记录的sign先后分别是1和-1,则在Merge的时候,两条记录会同时被删除。注意删除(折叠)规则如下:

  • 如果两条记录的写入顺序是 sign = -1 和 sign = 1,则两条记录都不会被删除。
  • 如果 sign = 1 和 sign = -1 的记录数是相等的,且最后一行是 sign = 1 的记录,则保留第一条sign = -1 的记录和最后一条sign = 1的记录,可以发现第一条规则就是第二条规则的特殊情况。
  • 如果 sign = 1 的记录数大于 sign = -1 的记录数,则保留最后一条 sign = 1 的记录。如果一种数据的数量比另一种多出两条或者两条以上,合并将照常进行,但ClickHouse将此情况视为逻辑错误,并将其记录在服务器日志中。
  • 如果 sign = -1 的记录数大于 sign = 1 的记录数,则保留第一条 sign = -1 的记录。
  • 其他情况不保留数据。

※注意: CollapsingMergeTree 也是后台操作,不是实时的,只有Merge的时候才会折叠(删除)数据,而且如果有多个任务在操作同一个表,可能会导致 sign 错乱,造成不可预知的结果,使用时要慎重考虑(建议使用下一节的VersionedCollapsingMergeTree表)。但是,CollapsingMergeTree 表无疑变相实现了delete和update操作,而且以空间换时间,提高了效率。当然,也可以通过 GROUP BY + HAVING sum(Sign) > 0 的形式查询:

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

也可以为FROM子句使用FINAL修饰符,但是这种方法的效率比较低,尤其不要用在大表上面:

SELECT * FROM UAct FINAL

或者当插入 sign = -1 的记录时,把关注的数值列同样取反插入,这样当查询计算sum(数值列)的时候,也可以不关注sign。

5. VersionedCollapsingMergeTree

根绝第4节CollapsingMergeTree的介绍可知,CollapsingMergeTree对数据的插入顺序是有严格要求的,不合理的插入顺序可能会导致难以预测的结果。针对这种情况,clickhouse又推出了VersionedCollapsingMergeTree表引擎。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 和 CollapsingMergeTree 一样,Int8类型,1 表示“state”(插入有效数据),-1 表示“cancel”(删除上一次插入的数据);参数 version 是版本控制字段,UInt* 类型。

VersionedCollapsingMergeTree 通过 version 列来控制乱序数据的折叠,对数据的写入顺序没有要求。但是 version 不同的记录不会相互折叠(删除),即使新的 version 更大,因为 VersionedCollapsingMergeTree 的实现方式是把 version 字段隐式加到 ORDER BY 最后。

同样,VersionedCollapsingMergeTree 也是在合并的时候才会进行折叠,因此在使用时最好通过聚合查询,例如统计数据量使用 sum(Sign),而不是 count(),求和使用 sum(Sign * x) + HAVING sum(Sign) > 0 代替 sum(x)。

总之,对于需要频繁删除、修改的数据 CollapsingMergeTree、VersionedCollapsingMergeTree 是一种合理、高效的表引擎,但是务必要注意数据写入顺序、数量的管理。

6. GraphiteMergeTree

GraphiteMergeTree 引擎表是为存储 Graphite 后台数据而设计的,可以用来优化rollup,使用较少。Graphite 是一个企业级的监控工具,可以在廉价的硬件上良好运行。

7. Data Replication

MergeTree 和上述 6 中表引擎都有对应的 Replication 表引擎,除了功能和各自对应表引擎一样外,还实现了副本功能,换句话说就是数据HA。表引擎名称分别是 Replicated 加对应表引擎名称,例如:ReplicatedMergeTree、ReplicatedReplacingMergeTree 等。因为副本表往往是和分片一起创建(通过集群),因此,关于副本和分片的配置、使用我们将在下一篇文章中一起详细介绍。

※ 注意: 和HDFS不同,ClickHouse MergeTree 家族表的副本机制是表级别的,不是库级别的,但是可以通过集群配置。另外,Replication 表功能是实现数据副本备份,不是横向扩展能力(横向扩展是通过分片来实现的),两个节点可以组成两副本表,存储数据一样,但是存储能力并没有增加。

参考文章

[1] https://blog.csdn.net/u012551524/article/details/112118734

ClickHouse MergeTree家族特殊表引擎相关推荐

  1. 【Clickhouse】Clickhouse MergeTree家族引擎

    文章目录 1.概述 2.工作原理 2.MergeTree的存储结构 3.数据分区 4. 一级索引 5.二级索引 6.数据存储 6.1 列独立存储: 6.2 压缩数据块 7.数据标记 8.分区索引和标记 ...

  2. 一文读懂ClickHouse(概述,安装,数据类型,表引擎,sql语法)

    第1章 ClickHouse概述 1.1 什么是ClickHouse ClickHouse 是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能 ...

  3. ClickHouse MergeTree表引擎和建表语句

    1. Clickhouse使用场景 ClickHouse是由俄罗斯Yandex公司开发的.面向列的数据库管理系统(DBMS),主要面向OLAP场景,用于在线分析处理查询,可以使用SQL查询实时生成数据 ...

  4. ClickHouse MergeTree副本表和分布式表(切片)

    在前面的文章中我们详细介绍了 MergeTree 表引擎.MergeTree 家族其他表引擎.MergeTree 二级索引等内容,clickhouse数据库都是在单节点上运行的,作为OLAP处理的大数 ...

  5. 【用户画像】ClickHouse中的数据类型、表引擎介绍及使用、项目几个问题的解决办法

    文章目录 一 数据类型 1 整型 2 浮点型 3 布尔型 4 Decimal 型 5 字符串 (1)String (2)FixedString(N) 6 时间类型 7 数组 8 元组 二 三个小问题 ...

  6. clickhouse表引擎-合并树系列

    目录 1 clickhouse表引擎-合并树系列简介 2 MergeTree引擎 2.1 建表语法 2.2 创建最简单的MergerTree引擎表 2.3 插入数据 2.4 查看目录结构 2.5 指定 ...

  7. ClickHouse表引擎到底怎么选

    引言 表引擎在ClickHouse中的作用十分关键,直接决定了数据如何存储和读取.是否支持并发读写.是否支持index.支持的query种类.是否支持主备复制等. ClickHouse提供了大约28种 ...

  8. 大数据培训ClickHouse表引擎

    表引擎 表引擎(即表的类型)决定了: 1)数据的存储方式和位置,写到哪里以及从哪里读取数据 2)支持哪些查询以及如何支持. 3)并发数据访问. 4)索引的使用(如果存在). 5)是否可以执行多线程请求 ...

  9. ClickHouse的表引擎介绍(三)

    文章目录 引入表引擎的概念以及特点 一.TinyLog 二.Memory 三.MergeTree 四.ReplacingMergeTree 五.SummingMergeTree 六.Integrati ...

最新文章

  1. linux下git的简单使用
  2. java dagger2_从零开始搭建一个项目(rxJava+Retrofit+Dagger2) ---上
  3. 英伟达联手Arm CPU打造AI超算,百万兆级性能,主攻气候变化和核武建模
  4. 记录安装mysql5.7.24遇到的坑
  5. PyQt5-菜单栏工具栏状态栏的使用(QMenuBar、QToolBar、QStatusBar)
  6. how to create Employee in SAP Cloud Platform
  7. 可是听了半天C++五子棋
  8. Tomcat JVM 初始化加大内存
  9. 【360开源】Quicksql——更简单,更安全,更快速的跨数据源统一SQL查询引擎
  10. Vivado生成bit文件报错彻底解决
  11. cds5516舵机控制程序_[电力世界]中的应用程序CDS
  12. 树莓派4支持多大tf卡_树莓派raspberry4B入坑指南 part-0
  13. 电力101/104规约文件服务报文浅析
  14. 广数系统加工中心编程_数控加工中心编程师傅亲述:提升编程水平的建议
  15. thymeleaf select 回显
  16. matlab 窗函数频谱,功率谱、频率分辨率、频谱泄漏与窗函数
  17. js 判断是不是数组
  18. linux affinity,Linux CPU Affinity
  19. 视频处理VideoCapture类---OpenCV-Python开发指南(38)
  20. 15本职场必读书,得挑几本看看!

热门文章

  1. Java语言-for循环详解
  2. Linux驱动开发(十)---树莓派输入子系统学习(红外接收)
  3. 《炬丰科技-半导体工艺》IPA溶液的界面和电动特性
  4. 在win7系统上装linux,在Windows操作系统中安装Linux系统
  5. 【两万字】IO流介绍大全,代码例题,内存图结构,一看就会
  6. 【开发测试个人小微接入短信验证码】thinkphp5.1+小程序使用短信验证码登录
  7. 共享充电桩APP开发详细方案
  8. PC市场逆势复苏之路:创新与多元化引领未来
  9. 古剑奇谭显示服务器维修,古剑奇谭OL出现千人混战,满地图都是红名,服务器差点打宕机...
  10. Makefile文件制作