
ClickHouse中除了常用的MergeTree引擎系列,还有很多其他用途的专门引擎,极大地扩展了clickhous的使用场景。这些专门用途的表引擎可以按照特性及使用大致分为5种类型,分别为外部存储类、内部存储类、日志类、接口类及除前面类型的其他类。
1. 外部存储类型
1.1 定义
clickhouse中划归为外部存储类型的表引擎直接从其他的存储系统读取数据,如直接读取HDFS的文件或者MySQL数据库的表。这些表引擎只负责元数据管理和数据查询,而它们自身通常并不负责数据的写入,数据文件直接由外部系统提供。基于这点其作用类似于数据访问客户端。
1.2 外部存储分类
1.HDFS表引擎
允许通过clickhouse管理HDFS中的数据、读取HDFS内的文件。但是不支持HDFS的Kerberos,需关闭。
定义:
ENGINE = HDFS(hdfs_uri,format)
hdfs_uri为HDFS文件的存储路径,format为文件格式。
两种用法:
(1)既负责读取也负责写入
(2)只负责读文件,写入由其他外部系统
2.mysql表引擎
与MySQL数据库中的数据表建立映射,但是只支持select、insert操作,不支持update、delete操作
定义:
ENGINE = MySQL('host:port','database','table','user','password'[,replace_query,'on_duplicate_clause'])
3.JDBC表引擎
mysql、PostgreSQL、SQLite和H2数据库对接,需要依赖名为clickhouse-jdbc-bridge(java编写)的查询代理服务。项目地址:https://github.com/ClickHouse/clickhouse-jdbc-bridge,对该项目进行编译。并在配置文件config.xml中做相应的配置即可,
定义:
ENGINE = JDBC('jdbc:url','database','table')
每次SELECT查询,JDBC表引擎先向clickhouse-jdbc-bridge发一次ping请求,探测代理是否启动。
* jdbc函数也可以通过代理查询:
select * from jdbc('jdbc:url','databases','table')
4.kafka表引擎
与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提交的频率
默认500ms拉取一次数据,时间由stream_poll_timeout_ms控制。先到缓存,再写入表中。
刷新缓存,写入表的过程中的相关配置:
1)数据块写入完成,块大小由kafka_max_block_size参数控制,默认为65536
2)等待超过7500毫秒,由stream_flush_interval_ms参数控制
连接kafka的底层使用librdkafka实现,由C++实现的Kafka库。
* 使用方式:kafka作为数据管道使用,建立过程为:
建立kafka引擎表A,从kafka拉取数据;
建立merge引擎表C,存储kafka的数据;
建立视图B,负责从A表同步数据至C;
用户从C查询数据。
create materialized view B to C as select id,code,name from A
删除视图:drop table B
卸载视图:detach table B
装载视图:
attach materialized view B to C (
id UInt32,
code String,
name String
)
as select id,code,name from A
5.File表引擎
支持直接读取本地文件的数据,导出数据为本地文件,可用于数据格式转换。
定义:
ENGINE = File(format)
File表引擎的数据文件只能保存在config.xml配置中由path指定的路径下。
2. 内部存储类型
2.1 定义
内部存储类型的引擎是面向内存查询的,数据会从内存中被直接访问。除了Memory表引擎之外,其它表引擎都将数据写入磁盘,是为了防止数据丢失,因此一般作为一种故障恢复手段。在数据表被加载时,它们会将数据全部加载至内存。
2.2 内部存储分类
1.Memory表引擎
该引擎是直接将数据保存在内存中,数据既不会被压缩也不会被格式转换。因为存于内存,因此重启后会丢失。存于内存中的数据,不需要读取磁盘、序列化等,可以并行执行。一般是作为集群间分发数据的存储载体,或者是中间表数据。
定义:
ENGINE = Memory()
2.Set表引擎
该引擎将数据写入内存并同步磁盘,重启会重新加载数据至内存。存储于该表的元素将会去重。可以间接作为 IN 条件后的数据。如:
select arrayJoin([1,2,3]) as a where a in set_table;
存储由[num].bin文件和tmp临时目录组成,先写tmp再写bin。
定义:
ENGINE = Set()
3.Join表引擎
该表可以使用select查询,主要是作为join表。如:
select id,name,price from new_table left join join_table using(id);
join函数访问:
select joinGet('join_table','price','toUInt8(1)');
定义:
ENGINE = Join(join_strictness,join_type,key1[,key2,...])
其中设置的参数含义如下:
join_strictness:连接精度all、any、asof
join_type:连接类型inner、outer、cross
key1:连接键,关联字段
4.Buffer表引擎
该引擎不支持文件的持久化存储,仅仅是充当缓冲区的角色。使用场景一般是在写入并发过多的时候,先将数据写入buffer表,buffer表再自动刷入目标表。
定义:
ENGINE = Buffer(database,table,num_layers,min_time,max_time,min_rows,max_rows,min_bytes,max_bytes)
其中参数的含义如下:
database:目标数据库,
table:目标表,
num_layers:刷入目标表的线程数,官方建议16,
min_time、max_time:第一次向表内写入数据计时,最小值和最大值
min_rows、max_rows:数据行数最小最大值
min_bytes、max_bytes:数据体量条件的最小和最大值,单位为字节
缓存表中的数据何时刷入磁盘,有如下规则(该规则是在每个num_layers中分别计算的):
三个最小值满足,刷入;
三个中至少有一个最大值满足,刷入;
超过max_rows或max_bytes,刷入。
3. 日志类型
3.1 定义
日志引擎是为了需要写入许多小数据量(少于一百万行)的表的场景而开发的。它们有一些共有的特性:不支持索引、分区。不支持并发读写,写入时阻塞读取。
3.2 日志分类
1.TiyLog
数据文件和元数据两部分,按列独立存储。不支持分区,也没有.mrk标记文件,不支持并发读取,sizes.json记录数据大小信息。
定义:
create table tinylog(
id UInt64,
code UInt64
)ENGINE = TinyLog()
2.StripeLog
一共存储三种数据文件:data.bin数据文件、index.mrk数据标记、sizes.json元数据文件。所有的列字段用同一个文件保存,拥有.mrk标记文件,支持并行查询。
定义:
create table stripelog(
id UInt64,
code UInt64
)ENGINE = StripeLog()
3.Log
该引擎是日志家族性能最高,支持和并行查询,按列按需读取。一共有三种数据存储文件:[column].bin数据文件、__marks.mrk数据标记文件、 sizes.json元数据文件。
定义:
create table log(
id UInt64,
code UInt64
)ENGINE = Log()
4. 接口类型
4.1 定义
接口类型的引擎其自身不存储数据,主要用于整合其他表。
4.2 接口分类
1.Merge
异步代理查询任意数量的数据库,并合成一个结果集。使用场景可以为:每个月有一张表,那么查询一整年数据使用merge可以一次查完。支持查询的表结构相同,引擎可以不同。
定义:
create table merge_table as table_2019
ENGINE = Merge(currentDatabase(),'table_')
该定义的含义为:使用table_2019相同的表结构,指定数据库和目标表前缀。并且在结果返回中添加虚拟列‘_table’,其可以当作索引查询。
比如:
select _table,* from merge_table where _table='table_2019'
2.Dictionary
数据字典表引擎。该字典会加载至内存,相当于通过查表的形式查询内存的字典。假设字典为dict,则建表语句为:
create table tb_dict(
id UInt64,
code String,
name String
)ENGINE = Dictionary(dict)
该引擎可以创建字典表库,为所有字典建立形式表。比如:
create database test_dictionaries ENGINE = Dictionary
clickhouse自动为每个字典创建Dictionary表。
3.Distributed
分布式表。该引擎将多个本地表组成分布式表。分布式引擎本身不存储数据, 但可以在多个服务器上进行分布式查询。读是自动并行的,且读取时远程服务器表的索引会被使用。
定义:
Distributed(logs, default, hits[, sharding_key])
5. 其他类型
5.1 定义
除以上分类的表引擎以外的类型。
5.2 接口分类
1.Live View
准实时数据处理有kafka表引擎、物化视图。事件监听机制视图有live view。其原理是将一条sql的查询结果作为监控目标,数据增加则进行响应。设置allow_experimental_live_view为1,检查参数是否正确:
select name,value from system.settings where name like '%live_view%''
建立流程如下:
1)创建原始表
create table origin_table(
id UInt64
)ENGINE = Log
2)创建live view
create live view lv_origin as select count() from origin_table
3)开启监听,即查询
watch lv_origin
2.Null
可以向null表写入数据,但数据不会被保存,查询返回为空表。一般场景为使用物化视图不想保存源表的数据,只希望查看视图的结果,则将源表设置为null表。
定义:
create table null_table(
id UInt64
)ENGINE = Null
3.URL
该引擎等价于http客户端,其原理为将select转换为get请求,insert转换为post请求,向指定的url地址进行请求。
定义:
create table url_table(
name String
)ENGINE = URL('http://service.ck.com:3000/user',JSONEachRow)
其中的format包括:TSV、CSV、JSON等。
* 一般使用场景下,如果数据大于1亿,则不建议使用内存类表引擎。
* 下期将总结clickhouse常用的查询语句。
参考资料:
[1] Yandex.clickhouse官方文档[EB/OL]:https://clickhouse.tech/docs/en/
[2] 朱凯.ClickHouse原理解析与应用实践[M]




