目录
一、 MergeTree系列引擎
1、MergeTree
数据TTL
(1) 列级别 TTL
(2) 表级别 TTL
存储策略
2、ReplacingMergeTree
3、CollapsingMergeTree
4、VersionedCollapsingMergeTree
5、SummingMergeTree
6、AggregatingMergeTree
二、 外部存储类引擎
1、HDFS表引擎
2、mysql表引擎
3、JDBC表引擎
4、Kafka 表引擎
5、File表引擎
三、内存类型引擎
1、memory表引擎
2、set表引擎
3、join表引擎
4、buffer表引擎
四、日志类型引擎
1、TinyLog表引擎
2、StripeLog 表引擎
3、Log表引擎
五、接口类型引擎
1、Merge 表引擎
2、Dictionary 表引擎
3、Distributed 表引擎
六、其他引擎
1、live view
2、Null
3、URL
在大数据分析领域,ClickHouse以其卓越的查询性能和高效的列式存储机制而著称。其背后的核心技术之一便是多样化的表引擎,它们针对不同的数据访问模式和存储需求进行了优化。本文旨在深入探讨ClickHouse中的各种表引擎,帮助你更好地理解它们的特性和应用场景
一、 MergeTree系列引擎
MergeTree系列是ClickHouse中最为强大和常用的引擎,适用于大规模数据的高效存储和查询,特别是时间序列数据。这类引擎的特点是支持高效的写入和合并操作,能够处理高吞吐量的数据插入和复杂查询。
1、MergeTree
MergeTree 作为家族系列最基础的表引擎,提供了数据分区、一级索引和二级索引等功能。
数据TTL
TTL 即 Time To Live,表示数据的存活时间,而在 MergeTree 中可以为某个列字段或整张表设置 TTL。当时间到达时,如果是列字段级别的 TTL,则会删除这一列的数据;如果是整张表级别的 TTL,则会删除整张表的数据;如果同时设置,则会以先到期的为主。
无论是列级别还是表级别的 TTL,都需要依托某个 DateTime 或 Date 类型的字段,通过对这个时间字段的 INTERVAL 操作来表述 TTL 的过期时间,下面我们看一下设置的方式。
(1) 列级别 TTL
需要在定义表字段的时候,为它们声明了 TTL 表达式,主键字段不能被声明 TTL。
CREATE TABLE ttl_table_v1 (id String,create_time DateTime,code String TTL create_time + INTERVAL 10 SECOND,type UInt8 TTL create_time + INTERVAL 10 SECOND
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(create_time)
ORDER BY id
(2) 表级别 TTL
CREATE TABLE ttl_table_v2 (id String,create_time DateTime,code String TTL create_time + INTERVAL 1 MINUTE,type UInt8
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(create_time)
ORDER BY create_time
TTL create_time + INTERVAL 1 DAY
建表的时候增加表级别的 TTL ,当触发 TTL 清理时,那些满足过期时间的数据行将被整行删除。TTL 支持修改,例如:
ALTER TABLE ttl_table_v2 MODIFY TTL create_time INTERVAL + 3 DAY
表级别的 TTL 不支持取消。
存储策略
ClickHouse 19.15 版本之前,MergeTree 只支持但路径存储,所有的数据都会被写入 config.xml 配置中 path 指定的路径下,即使服务器挂载了多块磁盘,也无法有效利用这些存储空间。19.15版本之后 MergeTree 实现了自定义存储策略的功能,支持以数据分区为最小移动单位,将分区目录写入多块磁盘目录。
三大存储侧策略:
- 默认策略:MergeTree 原本的存储策略,无须任何配置,所有分区会自动保存到 config.xml 配置中 path 指定的路径下。
- JBOD 策略:这种策略适合服务器挂载了多块磁盘,但没有做 RAID 的场景。数据可靠性需要利用副本机制保障。
- HOT/COLD 策略:这种策略适合服务器挂载了不同类型磁盘的场景。HOT 区域使用 SSD 这类高性能存储媒介,注重存储性能;COLD 区域使用 HDD 这类高容量存储媒介,注重存取经济性。数据会先写入 HOT 累积到阈值之后自行移动到 COLD 区。
2、ReplacingMergeTree
支持数据的更新和删除,通过版本控制来标记过期数据, MergeTree 拥有主键,但没有唯一约束,如果不希望数据表中有重复数据的场景可以使用 ReplacingMergeTree ,它可以在合并分区时删除重复的数据
。
创建方式:
ENGINE = ReplacingMergeTree(ver)
里面的参数 ver 是选填的,可以指定一个整型、Date、DateTime 的字段作为版本号,这个参数决定了去除重复数据时所使用的算法。
创建一个ReplacingMergeTree 数据表:
CREATE TABLE replace_table (id String,code String,create_time DateTime
) ENGINE = ReplacingMergeTree()
PARTITION BY toYYYYMM(create_time)
ORDER BY (id, code)
PRIMARY KEY id
上文中的order by 是去除重复数据的关键,数据会基于id 和 code 两个字段进行去重
测试如下
INSERT INTO replace_table
VALUES ('A001', 'C1', '2020-11-10 15:00:00'),('A001', 'C1', '2020-11-11 15:00:00'),('A001', 'C100', '2020-11-12 15:00:00'),('A001', 'C200', '2020-11-13 15:00:00'),('A002', 'C2', '2020-11-14 15:00:00'),('A003', 'C3', '2020-11-15 15:00:00')
create_time 为 2020-11-10 15:00:00、2020-11-11 15:00:00 的两条数据的 id 和 code 是重复的,因此会进行去重,只保留重复数据的最后一条
触发所有分区合并:
optimize TABLE table_name FINAL
总结一下 ReplacingMergeTree 的使用逻辑:
- 使用 ORDER BY 排序键作为判断数据重复的唯一键;
- 当导入同一分区目录时,会直接进行去重;
- 当导入不同分区目录时,不会进行去重,只有当分区目录合并时,属于同一分区内的重复数据才会去重;但是不同分区内的重复数据不会被删除;
- 在进行数据去重时,因为分区内的数据已经是基于 ORDER BY 排好序的,所以能很容易地找到那些相邻的重复的数据;
- 数据去重策略有两种:如果没有设置 ver 版本号,则保留同一组重复数据中的最后一条;如果设置了 ver 版本号,则保留同一组重复数据中 ver 字段取值最大的那一行。
3、CollapsingMergeTree
CollapsingMergeTree(折叠合并树) 就是一种通过以增代删的思路,支持行级数据修改和删除的表引擎。它通过定义一个 sign 标记位字段,记录数据行的状态。如果 sign 标记为 1,则表示这是一行有效数据;如果 sign 标记为 -1,则表示这行数据要被删除。当 CollapsingMergeTree 分区合并时,同一数据分区内,sign 标记为 1 和 -1 的一组数据(ORDER BY 字段对应的值相同)会被抵消删除。
创建方法
ENGINE = CollapsingMergeTree(sign)
sign 用于指定一个 Int8 类型的标志位字段,一个完整的 CollapsingMergeTree 数据表声明如下:
CREATE TABLE collapse_table (id String,code Int32,create_time DateTime,sign Int8
) ENGINE = CollapsingMergeTree(sign)
PARTITION BY toYYYYMM(create_time)
ORDER BY id
CollapsingMergeTree 在折叠数据时遵循如下规则:
- 如果 sign = 1 比 sign = -1 的数据多一行,则保留最后一行 sign = 1 的数据
- 如果 sign = -1 比 sign = 1 的数据多一行,则保留第一行 sign = -1 的数据
- 如果 sign = 1 和 sign = -1 的数据行一样多,并且最后一行是 sign = 1,则保留第一行 sign = -1 和最后一行 sign = 1 的数据
- 如果 sign = 1 和 sign = -1 的数据行一行多,并且最后一行是 sign = -1,则什么也不保留
- 其余情况,ClickHouse 会打印告警日志,但不会报错,在这种情形下打印结果不可预知
当然折叠数据并不是实时触发的,和所有的其它 MergeTree 变种表引擎一样,这项特性只有在多个分区目录合并的时候才会触发,触发时属于同一分区的数据会进行折叠。而在分区合并之前,用户还是可以看到旧数据的,就像上面演示的那样。
如果不想看到旧数据,那么可以在聚合的时候可以改变一下策略:
-- 原始 SQL 语句
SELECT id, sum(code), count(code), avg(code), uniq(code)
FROM collapse_table GROUP BY id-- 改成如下
SELECT id, sum(code * sign), count(code * sign), avg(code * sign), uniq(code * sign)
FROM collapse_table GROUP BY id HAVING sum(sign) > 0
或者在查询数据之前使用 optimize TABLE table_name FINAL 命令强制分区合并,但是这种方法效率极低,在实际生产环境中慎用
。
注意:
CollapsingMergeTree 的处理机制所要求 sign = 1 和 sign = -1 的数据相邻,而分区内的数据严格按照
ORDER BY 排序,要实现 sign = 1 和 sign = -1 的数据相邻,则只能严格按照顺序写入。
如果数据的写入顺序是单线程执行的,则能够比较好的控制写入顺序;但如果需要处理的数据量很大,数据的写入程序通常是多线程的,那么此时就不能保障数据的写入顺序了。而在这种情况下,CollapsingMergeTree 的工作机制就会出现问题
4、VersionedCollapsingMergeTree
VersionedCollapsingMergeTree 表引擎的作用和 CollapsingMergeTree 完全相同,它们的不同之处在于 VersionedCollapsingMergeTree 对数据的写入顺序没有要求,在同一个分区内,任意顺序的数据都可以完成折叠操作。那么 VersionedCollapsingMergeTree 是如何做到这一点的呢?其实从它的名字就能看出来,因为相比 CollapsingMergeTree 多了一个 Versioned,那么显然就是通过版本号(version)解决的。
在定义 VersionedCollapsingMergeTree 数据表的时候,除了指定 sign 标记字段之外,还需要额外指定一个 UInt8 类型的 ver 版本号字段。
ENGINE = VersionedCollapsingMergeTree(sign, ver)
一个完整的 VersionedCollapsingMergeTree 表定义如下:
CREATE TABLE ver_collapse_table (id String,code Int32,create_time DateTime,sign Int8,ver UInt8
) ENGINE = CollapsingMergeTree(sign, ver)
PARTITION BY toYYYYMM(create_time)
ORDER BY id
提问:VersionedCollapsingMergeTree 是如何使用版本号字段的呢?
答:在定义 ver 字段之后,VersionedCollapsingMergeTree 会自动将 ver 作为排序条件并增加到 ORDER BY 的末端。以上面的 ver_collapse_table 为例,在每个分区内,数据会按照 ORDER BY id, ver DESC 排序。所以,无论写入时数据的顺序如何,在折叠处理时,都能回到正确的顺序。
5、SummingMergeTree
能够在合并分区的时候按照预先定义的条件聚合汇总数据,减少查询时的计算开销和数据行数。
主要使用的场景是用户只关心汇总结果,不关心明细数据,并且数据汇总条件是预先明确的场景(GROUP BY 条件明确,且不会随意改变)
创建方法
ENGINE = SummingMergeTree((col1, col2, col3, ...))
其中 col1、col2 为 columns 参数值,这是一个选填参数,用于设置除主键外的其它数值类型字段,以指定被 SUM 汇总的列字段。如果不填写此参数,则会将所有非主键的数值类型字段进行汇总,下面就来创建一张 SummingMergeTree 表:
CREATE TABLE summing_table (id String,city String,v1 UInt32,v2 Float64,create_time DateTime
) ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(create_time)
PRIMARY KEY id
ORDER BY (id, city)
如果导入同一分区目录的数据有重复的,那么直接就聚合了,不同分区目录则不会聚合,而是在合并生成新分区目录的时候,再对属于同一分区的多个分区目录里的数据进行聚合。另外 SummingMergeTree 也支持嵌套类型的字段,在使用嵌套类型字段时,需要被 SUM 汇总的字段必须以以 Map 后缀结尾。
总结
- 只有 ORDER BY 排序键作为聚合数据的条件 Key
- 写入同一分区目录的数据会聚合之后在写入,而属于同一分区的不同分区目录的数据,则会在合并触发时进行汇总
- 不同分区的数据不会汇总到一起
- 如果在定义引擎时指定了 columns 汇总列(非主键的数值类型字段),则 SUM 会汇总这些列字段;如果未指定,则聚合所有非主键的数值类型字段
- 在进行数据汇总时,因为分区内的数据已经基于 ORDER BY 进行排序,所以很容易找到相邻也拥有相同 Key 的数据
- 在汇总数据时,同一分区内相同聚合 key 的多行数据会合并成一行,其中汇总字段会进行 SUM 计算;对于那些非汇总字段,则会使用第一行数据的取值
- 支持嵌套结构,但列字段名称必须以 Map 后缀结尾,并且默认以第一个字段作为聚合 Key。并且除了第一个字段以外,任何名称以 key、Id 或者 Type 为后缀结尾的字段都会和第一个字段组成复合 Key
6、AggregatingMergeTree
专为聚合查询设计,能够在插入数据时进行预聚合,加快GROUP BY查询。
AggregatingMergeTree 是 SummingMergeTree 升级版,有些数据立方体的意思,核心思想是以空间换时间的方法提升查询性能。首先,它能够在合并分区的时候按照预先定义的条件聚合数据。同时,根据预先定义的聚合函数计算数据并通过二进制的格式存入表内。通过将同一分组下的多行数据预先聚合成一行,既减少了数据行,又降低了后续聚合查询的开销。
创建方法
ENGINE = AggregatingMergeTree()
AggregatingMergeTree 没有任何额外的设置参数,在分区合并时,在每个数据分区内,会按照 ORDER BY 聚合。经常结合物化视图方式实现,首先创建底表:
CREATE TABLE agg_table_basic (id String,city String,code String,value UInt32
) ENGINE = MergeTree()
PARTITION BY city
ORDER BY (id, city)
通常使用 MergeTree 作为底表,用于存储全量的明细数据,并以此对外提供实时查询。接着,创建一张物化视图:
CREATE MATERIALIZED VIEW agg_view
ENGINE = AggregatingMergeTree()
PARTITION BY city
ORDER BY (id, city)
AS SELECTid, city,uniqState(code) AS code,sumState(value) AS value
FROM agg_table_basic
GROUP BY id, city
物化视图使用 AggregatingMergeTree 表引擎,用于特定场景的数据查询,相比 MergeTree,它拥有更高的性能。数据会自动同步到物化视图,并按照 AggregatingMergeTree 的引擎的规则进行处理,查询只对 agg_view 查询即可。
二、 外部存储类引擎
这类引擎用于与外部数据源的集成,使得ClickHouse可以直接读写其他数据库或文件系统中的数据。
1、HDFS表引擎
注意:我们需要关闭 HDFS 的 Kerberos 认证,因为 HDFS 表引擎还不支持 Kerberos,然后在 HDFS 上创建用于存放文件的目录。
CREATE TABLE hdfs_table1 (id UInt32,code String,name String
) ENGINE = HDFS('hdfs://localhost:6666/clickhouse/hdfs_table1', 'CSV')
-- HDFS('HDFS 的文件存储路径', '文件格式,如 CSV、TSV、JSON 等等')
-- 注:数据表的名字和 HDFS 文件系统上的文件名可以不一致
2、mysql表引擎
CREATE TABLE clickhouse_trade_info (id UInt32,column1 type,column2 type,......
) ENGINE = MySQL('localhost:3306', 'default', 'trade_info', 'root', '123456')
-- 显然这几个参数的含义不需要多说,但还有两个可选参数 replace_query 和 on_duplicate_clause
-- replace_query 默认为 0,如果设置为 1,会用 REPLACE INTO 代替 INSERT INTO
-- on_duplicate_clause 默认为 0,对应 MySQL 的 ON DUPLICATE KEY 语法,如果想启用该设置,那么需要设置为 1
3、JDBC表引擎
相对于 MySQL 表引擎而言,JDBC 表引擎不仅可以对接 MySQL 数据库还能够与 PostgreSQL、SQLite 和 H2 数据库对接。但是,JDBC 表引擎无法单独完成所有的工作,他需要依赖名为 clickhouse-jdbc-bridge 的查询代理服务。自行研究吧
ENGINE = JDBC('jdbc:url', 'database', 'table')
4、Kafka 表引擎
clickhouse支持kafka表引擎,kafka有三种语义
最多一次(At Most Once):可能出现消息丢失的情况,因为在这种情形下,一条消息在消费端最多被接收一次
最少一次(At Least Once):可能出现消息重复的情况,因为在这种情形下,一条消息在消费端允许被接收多次
精确一次(Exactly Once):数据不多不少,一条消息在消费端恰好被消费一次,这也是最理想的情况,因为消息不可能百分之百不丢失
kafka表引擎目前还不支持精确一次(Exactly Once)
ENGINE = Kafka()
SETTINGS kafka_broker_list = 'host:port,...',kafka_topic_list = 'topic1,topic2',kafka_group_name = 'group_name',kafka_format = 'data_format[,]',[kafka_row_delimiter = 'delimiter_symbol',][kafka_schema = '',][kafka_num_consumers = N,][kafka_skip_broken_message = N,][kafka_commit_every_batch = N]
其中带有方括号的表示选填项,下面依次介绍这些参数的作用:
- kafka_broker_list:表示 Broker 服务的地址列表,多个地址之间使用逗号分割
- kafka_topic_list:表示订阅的消息主题的名称列表,多个主题之间使用逗号分割,多个主题中的数据均被消费
- kafka_group_name:表示消费者组的名称,表引擎会依据此名称创建消费者组
- kafka_format:表示用于解析消息的数据格式,在消息的发送端,必须按照此格式发送消息。而数据格式也必须是 ClickHouse 提供的格式之一,例如 TSV、JSONEachRow 和 CSV 等
- kafka_row_delimiter:表示判定一行数据的结束符,默认为 '\0'
- kafka_schema:对应 Kafka 的 schema 参数
- kafka_num_consumers:表示消费者的数据量,默认值为 1,表引擎会依据此参数在消费者组中开启相应数量的消费者线程,当然线程数不要超过分区数,否则没有意义。因为在 kafka 的主题中,一个分区只能被某个消费者组里面的一个消费者消费(如果想被多个消费者消费,那么这些消费者一定要隶属于不同的消费者组)
- kafka_skip_broken_message:当表引擎按照预定格式解析数据出现错误时,允许跳过失败的数据的行数,默认值为 0,即不允许任何格式错误的情形发生。在此种情形下,只要 kafka 主题中存在无法解析的数据,数据表都将不会接收任何数据。如果将其设置成非 0 的正整数,例如设置为 10,则表示只要 kafka 主题中存在无法解析的数据的总数小于 10,数据表就能正常接收消息数据,而解析错误的数据会被自动跳过
- kafka_commit_every_batch:表示执行 kafka commit 的频率,因此这里提交偏移量的方式是手动提交,默认值为 0,即当一整个 Block 块完全写入数据表后才执行一次 commit。如果设置为 1,则每写完一个 Batch 批次的数据就会执行一次 kakfa commit(一次 Block 写入操作,由多次 Batch 写入操作而成)
5、File表引擎
File 表引擎能够直接读取本地文件的数据,例如系统生成的文件,还可以将数据导出为本地文件
File 表引擎的声明方式如下:
ENGINE = File(clickhouse支持的数据格式,例如TSV,CSV,JSONeachRow等),例如CREATE TABLE test_file_table
(`id` UInt32,`name` String
)
ENGINE = File('CSV')
由上可见没有文件路径,因为 File 表引擎的数据文件只能保存在 config.xml 配置中由 path 指定的路径下,也就是和其它的数据表在同一个路径下。
每张 File 数据表均由目录和文件组成,其中目录以表的名称命名,而数据文件则以 data.<format> 命名,比如 data.CSV、data.TSV 等等
三、内存类型引擎
除了 Memory 表引擎之外,其余的几款内存表引擎都会将数据写入磁盘,因为为了防止数据丢失,所以也提供了这种故障恢复手段。而在数据表被加载时,它们会将数据全部加载至内存,以供查询。
1、memory表引擎
Memory 表引擎直接将数据保存在内存中,数据即不会被压缩也不会被格式转换,因为基于内存,所以服务重启后会丢失。常见用途为测试和clickhouse内部用来集群间分发数据的存储载体
Memory 表引擎测试表:
CREATE TABLE test_memory_table
(`id` UInt32,`name` String
)
ENGINE = Memory()
当数据被写入后,磁盘上不会创建任何文件,如果服务重启那这张表也会消失
2、set表引擎
Set 表引擎是拥有物理存储的,数据首先会被写入内存,然后被同步到磁盘文件中。所以服务重启之后它的数据不会丢失,当数据表被重新状态时,文件数据会再次被全量加载到内存中,
CREATE TABLE test_set_table
(`id` UInt32
)
ENGINE = Set()
set表支持insert,不支持select,常用在查询条件的in查询里,如下
select age,name,id from tmp_table where arr in set_table
3、join表引擎
join表数据也会先写入内存,然后同步到磁盘,且支持select操作,它的主要用途是在内存中缓存较小的数据集,以便可以快速地与较大的数据集进行JOIN操作。Join
表引擎不是用于存储大量数据的主要表,而是作为辅助表,以加速查询性能
CREATE TABLE test_join_table
(`id` UInt32,`name` String
)
ENGINE = Join(join_strictness, join_type, key1[, key2, ...])案例如下
CREATE TABLE test_join_table
(`id` UInt32,`name` String
)
ENGINE = Join(ANY,LEFT,id)
其中各参数的含义如下:
join_strictness:连接精度,它决定了 JOIN 查询在连接数据时所使用的策略,目前支持 ALL、ANY、SEMI、ANTI 四种类型
join_type:连接类型,它决定了 JOIN 查询在组合左右两个数据集合的策略,目前支持 INNER、LEFT、RIGHT 和 FULL 四种类型
join_key:连接键,它决定了使用哪个列字段进行关联
4、buffer表引擎
Buffer 表引擎完全使用内存装载数据,不支持文件的持久化存储,所以当服务重启之后,表内的数据会被清空。Buffer 表引擎不是为了面向查询场景而设计的,它的作用是充当缓冲区的角色。
Buffer 表引擎的声明方式如下:
ENGINE = Buffer(database, table, num_layers, min_time, max_time, min_rows, max_rows, min_bytes, max_bytes)
里面参数的作用如下:
database:目标表的数据库
table:目标表,Buffer 表内的数据会自动刷新到目标表
num_layers:可以理解为线程数,Buffer 表会按照 num_layers 的数量开启线程,以并行的方式将数据刷新到目标表,官方建议设置为 16
Buffer 表并不是实时刷新数据的,只有在阈值条件满足时才会刷新,阈值条件由三个最小和最大值组成,含义如下:
min_time 和 max_time:时间条件的最小值和最大值,单位为秒,从第一次向表内写入数据时开始计算
min_rows 和 max_rows:数据行数条件的最小值和最大值
min_bytes 和 max_bytes:数据大小的最小值和最大值,单位为字节
针对以上条件,Buffer 表刷新数据的判断依据有三个,满足其中任意一个就会刷新数据:
三组条件中所有最小阈值都已满足,则触发刷新动作
三组条件中有一个最大阈值满足(这里是超过最大值),则触发刷新动作
如果写入一批数据的行数大运 max_rows 或者数据大小大于 max_bytes,则数据直接写入目标表
四、日志类型引擎
日志的表引擎也有一些共性特征:比如均不支持索引、分区等高级特性,不支持并发读写等等。当针对一张日志表写入数据时,针对这张表的查询会被阻塞,直至写入动作结束。但它们同时也拥有切实的物理存储,数据会被保存到本地文件中
1、TinyLog表引擎
TinyLog 是日志家族系列中性能最低的表引擎,它的存储结构由数据文件和元数据两部分组成。
TinyLog 表引擎测试表:
CREATE TABLE test_tinylog_table
(`id` UInt32,`name` String
)
ENGINE = TinyLog()
2、StripeLog 表引擎
StripeLog 对比 TinyLog 拥有更高的查询性能。
StripeLog 表引擎测试表:
CREATE TABLE test_stripelog_table
(`id` UInt32,`name` String
)
ENGINE = StripeLog()
3、Log表引擎
Log 表引擎结合了 TinyLog 表引擎和 StripeLog 表引擎的长处,是日志引擎中性能最高的表引擎。由于拥有数据标记且各列数据独立存储,所以 Log 既能够支持并行查询,又能够按列按需读取。Log 表引擎测试表:
CREATE TABLE test_log_table
(`id` UInt32,`name` String
)
ENGINE = Log()
五、接口类型引擎
1、Merge 表引擎
Merge 表引擎就如同一层使用了门面模式的代理,它本身不存储任何数据,也不支持数据写入,它的作用就如同它的名字,即负责合并多个查询结果集。
Merge 表引擎的声明方式如下:
ENGINE = Merge(database, table_name)
其中 database 为数据库的名称,table_name 为数据表的名称,它支持使用正式则表达式,比如 ^ 表示合并所有以 test 为前缀的数据表
例如有日期分区命名的表test_table_2019、test_table_2020、test_table_2021、test_table_2022、test_table_2023、test_table_2024
-- test_table_2019 保存了 2019 年的数据
CREATE TABLE test_table_2019 (id String,create_time DateTime,code String
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(create_time)
ORDER BY id;2020-2024同上然后创建 Merge 表将上面两张表结合,这里的 AS 相当于为 merge_test_table_2019_2024 指定表结构
显然这里会复制 test_table_2019 的表结构
CREATE TABLE merge_test_table_2019_2024 AS test_table_2019
ENGINE = Merge(currentDatabase(), '^test_table_20')
-- currentDatabase() 表示获取当前的数据库
上面的语句是将所有以^test_table_20开头的数据表合并。
2、Dictionary 表引擎
Dictionary 表引擎是数据字段的一层代理封装,它可以取代字典函数,让用户通过数据表查询字典。字典内的数据被加载后,会全部保存到内存中,所以使用 Dictionary 表对字典表性能不会有任何影响。
Dictionary 表引擎测试表:
CREATE TABLE tb_test_flat_dict
(`id` UInt32,`code` String,`name` String
)
ENGINE = Dictionary(dict_name)
dict_name对应一个已被加载的字典名称
3、Distributed 表引擎
Distributed 表引擎自身不存储任何数据,它能作为分布式表的一层透明代理,在集群内部自动开展数据的写入分发以及查询路由工作。
六、其他引擎
1、live view
从 19.14 版本开始,ClickHouse 提供了一种全新的视图:Live View。
Live View 是一种特殊的视图,虽然它并不属于表引擎,但是因为它与数据表息息相关,所以还是把 LiveView 归类到了这里。Live View 的作用类似事件监听器,它能够将一条 SQL 查询结果作为监控目标,当目标数据增加时,LiveView 可以及时发出响应。若要使用 Live View,首先需要将 allow_experimental_live_view 参数设置为 1
原始表
CREATE TABLE origin_table1
(`id` UInt32,`name` String
)
ENGINE = Log()
创建一张 Live View 表示:
CREATE LIVE VIEW lv_origin AS SELECT COUNT(*) FROM orign_table1
如此一来,Live View 就进入监听模式了。接着通过下面的命令可以看出实时监控结果:
WATCH lv_origin
2、Null
Null 表引擎的功能和作用,与 Unix 系统的空设备 /dev/null 很相似。如果用户向 Null 表写入数据,系统会正确返回,但是 Null 表会自动忽略数据,永远不会将它保存。如果不希望保留源表的数据,那么将原表设置成 Null 引擎将会是极好的选择。
3、URL
URL 表引擎的作用等价于 HTTP 客户端,他可以通过 HTTP/HTTPS 协议,直接访问远端的 REST 服务。当执行 SELECT 查询的时候,底层会将其转换成 GET 请求的远程调用。而执行 INSERT 查询的时候,会将其转换为 POST 请求的远程调用。URL 表引擎的声明方式如下:
ENGINE = URL(url, format)
其中,url 表示远端的服务地址,而 format 则是 Clickhouse 支持的数据格式,如 TSV、CSV 和 JSON 等。