篇二啥是ClickHouse的表引擎?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了篇二啥是ClickHouse的表引擎?相关的知识,希望对你有一定的参考价值。

参考技术A

在上一篇分享中,我们介绍了ClickHouse的安装部署和简单使用。本文将介绍ClickHouse中一个非常重要的概念— 表引擎(table engine) 。如果对mysql熟悉的话,或许你应该听说过InnoDB和MyISAM存储引擎。不同的存储引擎提供不同的存储机制、索引方式、锁定水平等功能,也可以称之为 表类型 。ClickHouse提供了丰富的表引擎,这些不同的表引擎也代表着不同的 表类型 。比如数据表拥有何种特性、数据以何种形式被存储以及如何被加载。本文会对ClickHouse中常见的表引擎进行介绍,主要包括以下内容:

Log系列表引擎功能相对简单,主要用于快速写入小表(1百万行左右的表),然后全部读出的场景。 即一次写入多次查询

该引擎适用于 一次写入,多次读取的场景 。对于处理小批数据的中间表可以使用该引擎。值得注意的是,使用大量的小表存储数据,性能会很低。

进入默认数据存储目录,查看底层数据存储形式,可以看出: TinyLog 引擎表每一列都对应的文件

当我们执行 ALTER操作 时会报错,说明该表引擎不支持ALTER操作

相比TinyLog而言,StripeLog拥有更高的查询性能(拥有.mrk标记文件,支持并行查询),同时其使用了更少的文件描述符(所有数据使用同一个文件保存)。

进入默认数据存储目录,查看底层数据存储形式

可以看出StripeLog表引擎对应的存储结构包括三个文件:

Log引擎表适用于临时数据,一次性写入、测试场景。Log引擎结合了TinyLog表引擎和StripeLog表引擎的长处,是Log系列引擎中性能最高的表引擎。

进入默认数据存储目录,查看底层数据存储形式

Log引擎的存储结构包含三部分:

在所有的表引擎中,最为核心的当属MergeTree系列表引擎,这些表引擎拥有最为强大的性能和最广泛的使用场合。对于非MergeTree系列的其他引擎而言,主要用于特殊用途,场景相对有限。而MergeTree系列表引擎是官方主推的存储引擎,支持几乎所有ClickHouse核心功能。

MergeTree在写入一批数据时,数据总会以数据片段的形式写入磁盘,且数据片段不可修改。为了避免片段过多,ClickHouse会通过后台线程,定期合并这些数据片段,属于相同分区的数据片段会被合成一个新的片段。这种数据片段往复合并的特点,也正是合并树名称的由来。

MergeTree作为家族系列最基础的表引擎,主要有以下特点:

查看一下数据存储格式,可以看出,存在三个分区文件夹,每一个分区文件夹内存储了对应分区的数据。

进入一个分区目录查看

可以看出,新插入的数据新生成了一个数据块,并没有与原来的分区数据在一起,我们可以执行 optimize 命令,执行合并操作

执行上面的合并操作之后,会新生成一个该分区的文件夹,原理的分区文件夹不变。

上文提到 MergeTree 表引擎无法对相同主键的数据进行去重,ClickHouse提供了ReplacingMergeTree引擎,可以针对相同主键的数据进行去重,它能够在合并分区时删除重复的数据。值得注意的是, ReplacingMergeTree 只是在一定程度上解决了数据重复问题,但是并不能完全保障数据不重复。

当我们再次向该表插入具有相同主键的数据时,观察查询数据的变化

从上面的示例中可以看出,ReplacingMergeTree是支持对数据去重的,那么是根据什么进行去重呢?答案是: ReplacingMergeTree在去除重复数据时,是以ORDERBY排序键为基准的,而不是PRIMARY KEY 。我们在看一个示例:

再次向该表中插入相同emp_id和name的数据,并执行合并操作,再观察数据

至此,我们知道了ReplacingMergeTree是支持去重的,并且是按照 ORDERBY排序键 为基准进行去重的。细心的你会发现,上面的重复数据是在一个分区内的,那么如果重复的数据不在一个分区内,会发生什么现象呢?我们再次向上面的 emp_replacingmergetree1 表插入不同分区的重复数据

ReplacingMergeTree在去除重复数据时,是以ORDERBY排序键为基准的,而不是PRIMARY KEY。

在执行分区合并时,会触发删除重复数据。optimize的合并操作是在后台执行的,无法预测具体执行时间点,除非是手动执行。

ReplacingMergeTree是以分区为单位删除重复数据的。只有在相同的数据分区内重复的数据才可以被删除,而不同数据分区之间的重复数据依然不能被剔除。

如果没有设置 [ver]版本号 ,则保留同一组重复数据中的最新插入的数据; 如果设置了 [ver]版本号 ,则保留同一组重复数据中 ver字段取值最大的那一行

一般在数据量比较大的情况,尽量不要使用该命令。因为在海量数据场景下,执行optimize要消耗大量时间

该引擎继承了MergeTree引擎,当合并 SummingMergeTree 表的数据片段时,ClickHouse 会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值,即如果存在重复的数据,会对对这些重复的数据进行合并成一条数据,类似于group by的效果。

推荐将该引擎和 MergeTree 一起使用。例如,将完整的数据存储在 MergeTree 表中,并且使用 SummingMergeTree 来存储聚合数据。这种方法可以避免因为使用不正确的主键组合方式而丢失数据。

如果用户只需要查询数据的汇总结果,不关心明细数据,并且数据的汇总条件是预先明确的,即 GROUP BY的分组字段是确定的 ,可以使用该表引擎。

当我们再次插入具有相同emp_id,name的数据时,观察结果

要保证 PRIMARY KEY expr 指定的主键是 ORDER BY expr 指定字段的前缀,比如

这种强制约束保障了即便在两者定义不同的情况下,主键仍然是排序键的前缀,不会出现索引与数据顺序混乱的问题。

用ORBER BY排序键作为聚合数据的条件Key。即如果排序key是相同的,则会合并成一条数据,并对指定的合并字段进行聚合。

以数据分区为单位来聚合数据。当分区合并时,同一数据分区内聚合Key相同的数据会被合并汇总,而不同分区之间的数据则不会被汇总。

如果没有指定聚合字段,则会按照非主键的数值类型字段进行聚合

如果两行数据除了排序字段相同,其他的非聚合字段不相同,那么在聚合发生时,会保留最初的那条数据,新插入的数据对应的那个字段值会被舍弃

该表引擎继承自MergeTree,可以使用 AggregatingMergeTree 表来做增量数据统计聚合。如果要按一组规则来合并减少行数,则使用 AggregatingMergeTree 是合适的。AggregatingMergeTree是通过预先定义的聚合函数计算数据并通过二进制的格式存入表内。

与SummingMergeTree的区别在于:SummingMergeTree对非主键列进行sum聚合,而AggregatingMergeTree则可以指定各种聚合函数。

对于AggregateFunction类型的列字段,在进行数据的写入和查询时与其他的表引擎有很大区别,在写入数据时,需要调用 <agg>-State 函数;而在查询数据时,则需要调用相应的 <agg>-Merge 函数。对于上面的建表语句而言,需要使用 sumState 函数进行数据插入

上面演示的用法非常的麻烦,其实更多的情况下,我们可以结合物化视图一起使用,将它作为物化视图的表引擎。而这里的物化视图是作为其他数据表上层的一种查询视图。

AggregatingMergeTree通常作为物化视图的表引擎,与普通MergeTree搭配使用。

CollapsingMergeTree就是一种通过以增代删的思路,支持行级数据修改和删除的表引擎。它通过定义一个sign标记位字段,记录数据行的状态。如果sign标记为1,则表示这是一行有效的数据;如果sign标记为-1,则表示这行数据需要被删除。当CollapsingMergeTree分区合并时,同一数据分区内,sign标记为1和-1的一组数据会被抵消删除。

每次需要新增数据时,写入一行sign标记为1的数据;需要删除数据时,则写入一行sign标记为-1的数据。

上面的建表语句使用CollapsingMergeTree(sign),其中字段sign是一个Int8类型的字段

CollapsingMergeTree同样是以ORDER BY排序键作为判断数据唯一性的依据。

分数数据折叠不是实时的,需要后台进行Compaction操作,用户也可以使用手动合并命令,但是效率会很低,一般不推荐在生产环境中使用。

当进行汇总数据操作时,可以通过改变查询方式,来过滤掉被删除的数据

只有相同分区内的数据才有可能被折叠。其实,当我们修改或删除数据时,这些被修改的数据通常是在一个分区内的,所以不会产生影响。

值得注意的是:CollapsingMergeTree对于写入数据的顺序有着严格要求,否则导致无法正常折叠。

如果数据的写入程序是单线程执行的,则能够较好地控制写入顺序;如果需要处理的数据量很大,数据的写入程序通常是多线程执行的,那么此时就不能保障数据的写入顺序了。在这种情况下,CollapsingMergeTree的工作机制就会出现问题。但是可以通过VersionedCollapsingMergeTree的表引擎得到解决。

上面提到CollapsingMergeTree表引擎对于数据写入乱序的情况下,不能够实现数据折叠的效果。VersionedCollapsingMergeTree表引擎的作用与CollapsingMergeTree完全相同,它们的不同之处在于,VersionedCollapsingMergeTree对数据的写入顺序没有要求,在同一个分区内,任意顺序的数据都能够完成折叠操作。

VersionedCollapsingMergeTree使用 version 列来实现乱序情况下的数据折叠。

可以看出:该引擎除了需要指定一个sign标识之外,还需要指定一个UInt8类型的version版本号。

七十六ClickHouse的表引擎以及SQL语法

上一篇文章我们介绍了一下ClickHouse的安装,这一篇我们主要来看一下它的表引擎已经SQL语法。关注专栏《破茧成蝶——大数据篇》,查看更多相关的内容~


目录

一、ClickHouse的数据类型

二、ClickHouse的表引擎

2.1 TinyLog

2.2 Memory

2.3 Merge

2.4 MergeTree

2.5 ReplacingMergeTree

2.6 SummingMergeTree

2.7 Distributed

三、ClickHouse的SQL语法

3.1 CREATE

3.2  INSERT INTO

3.3 ALTER

3.4 查看表结构

3.5 CHECK TABLE


一、ClickHouse的数据类型

在介绍表引擎和SQL语法之前,我们先来看一下它的数据类型。常用的数据类型如下所示:

1、整型。固定长度的整型,包括有符号整型(-2n-1~2n-1-1)和无符号整型(0~2n-1)。

2、浮点型。建议尽可能以整数形式存储数据。例如,将固定精度的数字转换为整数值,如时间用毫秒为单位表示,因为浮点型进行计算时可能引起四舍五入的误差。与标准SQL相比,ClickHouse 支持以下类别的浮点数:Inf-正无穷、-Inf-负无穷、NaN-非数字。

3、布尔类型。没有单独的类型来存储布尔值。可以使用UInt8类型,取值限制为0或1。

4、字符串。(1)String:字符串可以任意长度的。它可以包含任意的字节集,包含空字节。(2)FixedString(N):固定长度N的字符串,N必须是严格的正自然数。当服务端读取长度小于N的字符串时候,通过在字符串末尾添加空字节来达到N字节长度。当服务端读取长度大于N的字符串时候,将返回错误消息。与String相比,极少会使用FixedString,因为使用起来不是很方便。

5、枚举类型。包括Enum8和Enum16类型,Enum保存'string'=integer的对应关系,Enum8用'String'=Int8对描述,Enum16用'String'=Int16对描述。

6、数组。Array(T):由T类型元素组成的数组。T可以是任意类型,包含数组类型。但不推荐使用多维数组,ClickHouse对多维数组的支持有限。

7、元组。Tuple(T1, T2, ...):元组,其中每个元素都有单独的类型。

8、Date类型。日期类型,用两个字节存储,表示从1970-01-01 (无符号) 到当前的日期值。

此处仅列举出8中数据类型,更多数据类型可以参考官方文档

二、ClickHouse的表引擎

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

ClickHouse的表引擎有很多,下面只介绍其中几种,对其他引擎有兴趣的可以去查阅官方文档

2.1 TinyLog

最简单的表引擎,用于将数据存储在磁盘上。每列都存储在单独的压缩文件中,写入时,数据将附加到文件末尾。该引擎没有并发控制,如果同时从表中读取和写入数据,则读取操作将抛出异常;如果同时写入多个查询中的表,则数据将被破坏。这种表引擎的典型用法是write-once:首先只写入一次数据,然后根据需要多次读取。此引擎适用于相对较小的表(建议最多1,000,000行)。如果有许多小表,则使用此表引擎是适合的,因为它比需要打开的文件更少。当拥有大量小表时,可能会导致性能低下。同时,它不支持索引。

下面我们来看一个简单的案例:创建一个TinyLog的表并插入数据。

我们可以到保存数据的目录下进行查看:

id.bin和name.bin是压缩过的对应的列的数据,sizes.json中记录了每个*.bin文件的大小:

2.2 Memory

内存引擎,数据以未压缩的原始形式直接保存在内存当中,服务器重启数据就会消失。读写操作不会相互阻塞,不支持索引。简单查询下有非常非常高的性能表现(超过10G/s)。

一般用到它的地方不多,除了用来测试,就是在需要非常高的性能,同时数据量又不太大(上限大概1亿行)的场景。

2.3 Merge

Merge引擎(不要跟MergeTree引擎混淆)本身不存储数据,但可用于同时从任意多个其他的表中读取数据。读是自动并行的,不支持写入。读取时,那些被真正读取到数据的表的索引(如果有的话)会被使用。 

Merge引擎的参数:一个数据库名和一个用于匹配表名的正则表达式。

下面我们来看一个简单的案例:我们先建三个表,然后使用Merge引擎将其连接起来。

1、首先穿件三张表并插入数据

create table t1 (id UInt16, name String) ENGINE=TinyLog;
create table t2 (id UInt16, name String) ENGINE=TinyLog;
create table t3 (id UInt16, name String) ENGINE=TinyLog;

insert into t1(id, name) values (1, 't1');
insert into t2(id, name) values (2, 't2');
insert into t3(id, name) values (3, 't3');

2、创建Merge引擎表并查询

2.4 MergeTree

ClickHouse中最强大的表引擎当属MergeTree(合并树)引擎及该系列(*MergeTree)中的其他引擎。MergeTree引擎系列的基本理念如下。当你有巨量数据要插入到表中,你要高效地一批批写入数据片段,并希望这些数据片段在后台按照一定规则合并。相比在插入时不断修改(重写)数据进存储,这种策略会高效很多。其语法格式如下:

ENGINE [=] MergeTree(date-column [, sampling_expression], (primary, key), index_granularity)

参数释义:

1、date-column:类型为Date的列名。ClickHouse会自动依据这个列按月创建分区,分区名格式为 "YYYYMM"。

2、sampling_expression:采样表达式。

3、(primary, key):主键,类型为Tuple()。

4、index_granularity:索引粒度,即索引中相邻”标记”间的数据行数。设为8192可以适用大部分场景。

我们通过一个简单的案例来看一下:

1、首先新建people表并向表中插入几条数据,如下:

create table people (date  Date, id UInt8, name String) ENGINE=MergeTree(date, (id, name), 8192);

insert into people values ('2021-05-01', 1, 'xzw');
insert into people values ('2021-06-01', 2, 'fq');
insert into people values ('2021-05-03', 3, 'yxy');

2、我们在对应的数据目录下可以看到如下内容:

其中,*.bin是按列保存数据的文件,*.mrk保存块偏移量,primary.idx保存主键索引。

2.5 ReplacingMergeTree

这个引擎是在MergeTree的基础上,添加了“处理重复数据”的功能,该引擎和MergeTree的不同之处在于它会删除具有相同主键的重复项。数据的去重只会在合并的过程中出现。合并会在未知的时间在后台进行,所以你无法预先作出计划。有一些数据可能仍未被处理。因此,ReplacingMergeTree适用于在后台清除重复的数据以节省空间,但是它不保证没有重复的数据出现。其语法格式如下:

ENGINE [=] ReplacingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity, [ver])

可以看出他比MergeTree只多了一个ver,这个ver指代版本列,他和时间一起配置,区分哪条数据是最新的。

2.6 SummingMergeTree

该引擎继承自MergeTree。区别在于:当合并SummingMergeTree表的数据片段时,ClickHouse会把所有具有相同主键的行合并为一行,该行包含了被合并的行中具有数值数据类型的列的汇总值。如果主键的组合方式使得单个键值对应于大量的行,则可以显著的减少存储空间并加快数据查询的速度,对于不可加的列,会取一个最先出现的值。其语法格式如下:

ENGINE [=] SummingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity, [columns])

其中,columns是指包含将要被汇总的列的列名的元组。

2.7 Distributed

分布式引擎,本身不存储数据, 但可以在多个服务器上进行分布式查询。 读是自动并行的。读取时,远程服务器表的索引(如果有的话)会被使用。其语法格式如下:

Distributed(cluster_name, database, table [, sharding_key])

其中,cluster_name是指服务器配置文件中的集群名,在/etc/metrika.xml中配置的。sharding_key是指数据分片键。

三、ClickHouse的SQL语法

3.1 CREATE

1、CREATE DATABASE

CREATE DATABASE [IF NOT EXISTS] db_name

2、CREATE TABLE

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
    ...
) ENGINE = engine

3.2  INSERT INTO

INSERT INTO [db.]table [(c1, c2, c3)] VALUES (v11, v12, v13), (v21, v22, v23), ...

3.3 ALTER

ALTER只支持MergeTree系列,Merge和Distributed引擎的表,基本语法如下所示:

ALTER TABLE [db].name [ON CLUSTER cluster] ADD|DROP|MODIFY COLUMN ...

3.4 查看表结构

DESCRIBE TABLE

3.5 CHECK TABLE

检查表中的数据是否损坏,他会返回两种结果:0表示数据已损坏;1表示数据完整。该命令只支持Log、TinyLog和StripeLog引擎。

 

以上就是本文的所有内容,比较简单。你们在此过程中遇到了什么问题,欢迎留言,让我看看你们都遇到了哪些问题~

以上是关于篇二啥是ClickHouse的表引擎?的主要内容,如果未能解决你的问题,请参考以下文章

七十六ClickHouse的表引擎以及SQL语法

clickhouse索引

客快物流大数据项目(九十二):ClickHouse的MergeTree系列引擎介绍和MergeTree深入了解

Code: 210. DB::NetException: Connection refused (localhost:9000)

15_clickhouse,MySQL引擎;MySQL和ClickHouse中数据类型的对应关系

如何在clickhouse中更改kafka引擎的设置