用了一段时间的CK了,给我的感受就是这玩意确实很强大,它的强大之处在于,这个数据库跟其他普通的数据库相比,除了提供高效的数据查询引擎外,还超越一般数据库的功能,提供各种外部数据源的接入,转换,和存储。
也就是说它除了提供数据库功能外,还干了很多专业的ETL工具,甚至计算引擎才能办到的事情,而这些功能,全部都是通过选择不同的表引擎来实现的。
CK的表引擎根据不同的大应用场景,将其划分为4大类:

这篇文章就根据我的理解以及具体的使用经验,来对它们做个简单的解读。
1. MergeTree Family引擎
这是一个引擎家族,意味着跟它一伙的子类引擎还有多个,该类型引擎在官网的解释是:功能最强大,使用最多,数据负载量最大的引擎。

这个家族的表引擎,最大的一个特点就是:异步 + 多线程。
数据异步写入后,会以多线程的方式,将数据落入到多个临时目录的临时文件中(之前文章内容展示过),而这每个临时文件都被叫做一个个data part,然后后台再启动多线程对数据进行异步合并,形成最终的数据文件,而这个特点应该就是这个Merge名字的由来。
此外,这个Tree代表的是CK的底层存储数据结构是树形结构,意味着每个data part就是一个个小的tree,后台的多线程会随时将这些data part给merger成若干个大文件,所以也叫MergeTree。
1.1 MergeTree引擎
这是MergeTree家族引擎中的父辈,是所有其他XXXMergeTree引擎的基础,所有其他引擎也都是基于它的基础功能衍生升级而来。
虽然是基础引擎,但是它依然提供了强大的功能,但是相对于其他普通数据库来说,这个引擎有些不一样的地方在于,你在建表的时候必须指定它的order by字段,而这就是它在数据写入时候的排序依据。
我们知道,对于一个有索引的数据库来说,索引的过程就是排序的过程,只不过,普通数据库是通过primary key或者index这样的声明方式告知索引字段,而CK则是用order by语句,这种告知方式我认为更加直接。
而更有意思的是,虽然CK也提供了primary key的字句,但是它的地位是远不如order by的,前者是可选,后者是必须,所以说primary key几乎没什么存在感。

此外,该引擎支持数据分区,这个就跟hive的建分区表有些像,其目的其实是一样的,就是将数据根据业务字段把数据的存储位置进一步打散,在查询时好过虑掉无关的数据。
适合场景:所有需要高效查询的本地表场景。
1.2 ReplicatedMergeTree引擎
这个跟普通的MergeTree引擎没有什么两样,只不过,它多提供了一个备份功能而已。
但是,就是因为多了个备份的功能,需要你配置一个额外的“中间人”角色,比如zookeeper,因为对于CK来说,你没有特殊指定,这个表它就是本地表(只在当前机器上)。
关于这块的详细内容可以看之前的文章:
适合场景:所有需要数据在多台机器上备份的场景。
1.3 ReplacingMergeTree引擎
这个表引擎从名字Replacing中就能大概能猜出它是干嘛的,它就是在普通MergeTree引擎的基础上多了一个去重功能。
CK有个特别大的特点就是,在所有的表引擎中,你声明的primary key字段是不具备去重能力的,更让人生气的是,即便你用了这个专业的去重引擎,它去重的依据依然不是primary key,而是order by指定的字段。

但是这里需要思考一个问题就是,既然是根据order by字段的值去重,那么去掉哪些保留哪些呢?
因为毕竟除了order by声明的字段数据一样外,其他字段的数据可能不一样啊。
这个引擎给了你一个ver选型,就是用来解决这个问题的:

啥意思呢?这个ver字段是可选的,如果不填,那么默认保留重复数据中最新写入的那条。
如果指定,必须是数值类型的字段,那么就选这个字段值最大那条保留下来。

适合场景:数据不能重复的精确一次性消费场景。
1.4 SummingMergeTree引擎
如果说上面那个引擎是将相同条件的数据聚合后,只保留最新的,那么这个引擎就是将相同条件的数据聚合后,根据指定字段(如果指定了的话)的值相加,并得出最终结果。
这个引擎相对于后面要说的AggregatingMergeTree,虽然也叫聚合引擎,但是它只能支持sum功能的轻度聚合,也就是根据order by后,有着相同值的数据进行相加合并。
但是这个合并,一般来说需要你指定具体要合并(相加)的字段(可以指定多个),而且这些字段类型必须是数值类型(因为要相加嘛),当然,这个字段必须是除order by字段之外的,否则就没有意义了。

如果你不指定相加字段的话,那么CK就会把其他除order by字段之外的,所有数值类型的字段值进行相加。

适合场景:根据特定字段进行sum聚合的场景,是最简单的聚合引擎。
1.5 AggregatingMergeTree引擎
正儿八经的聚合引擎,如果说上面的SummingMergeTree是小打小闹的话,那么这个应该就是能全方位多角度的满足你的各种业务聚合需求了。
这种聚合引擎的出现,在很大程度上省去了很多开发成本,以及需要聚合结果时的计算成本,因为这些,都是原始数据在写入该引擎表时,后台默默就给做了的。
关于该引擎的详细使用说明,可以参考旧文:。
适合场景:任何需要对实时数据进行各种维度的聚合场景。
1.6 CollapsingMergeTree引擎
这个引擎在我看来多少有点鸡肋,它的目的应该是用来记录数据变化的,有点类似数仓建模中,我们用来记录维度变化的拉链表。
拉链表最大的麻烦在于:每次数据写入时,需要判断要写入的数据是新增的还是修改的,为了搞清楚这一点,你就必须得老老实实去对比之前的老数据,你才能知道。
而这个CollapsingMergeTree也是一个道理,说是可以记录每条数据的更新变化,但前提是:你得知道当前的数据是不是更新的,所以你还是得去查。
官方给的例子中,对于变化的数据它是有一个专门的标签的:

只有你知道了这个标签,你才能用上该引擎提供的功能,但关键是我如果知道了这个是否更新的标签,我压根就可以不用你这个引擎啊。
适合场景:个人感觉比较鸡肋。
1.7 其他MergeTree引擎
虽然官网也都有介绍,但是个人觉得使用的场景比较狭窄,暂时没有去研究。
2. Log Family家族
这个家族的引擎个人理解应该是用的不太多的,因为它最大的特点就是没有索引,所以意味着你单表不可能存储太大的数据,以及查询效率不会很高。

官方提供它的使用场景,是用来存储一个个约100w数据量的小表,然后它的数据是被你连续读取的,该家族提供了3种引擎。
适合场景:数据量小的场景。
2.1 TinLog引擎
这个引擎是这个家族最差劲的,不但没有索引,就连数据读取时的多线程都不支持。
2.2 Log引擎
不支持索引,但是支持多线程读和写,而且数据是根据列写到多个文件中的。
2.3 Stripelog引擎
虽然不支持索引,且只写入到一个数据文件中,但是支持文件的marks,用来支持多线程查询。
3. Integration引擎
这个应该算是CK这个数据库的一大特色,意思是CK可以作为多个外部数据源(含数据库、文件系统、消息队列等)的客户端,将数据接入到CK内部保存起来。
这个功能最大的好处在于,省去了数据导入工具的使用,以前可能会针对不同的数据库用很多不同的导入工具,比如Sqoop、dataX等等。
而现在,创建不同数据源的引擎表就可以把数据直接导入到CK中,而且它支持当下大部分的主流数据库,文件系统,以及消息队列。
该引擎在使用时,一般跟后面提到的物化视图引擎一起使用,具体例子可参考旧文:
适合场景:需要把外部数据源接入到CK内部的场景。
4. Special引擎
叫特殊的表引擎,官方的解释是,凡是上面3个都没有包含的表引擎,但是CK又支持的建表方式,就都归纳到这里了。
这里的引擎种类同样也有很多,重点主要说2个。
4.1 Distributed引擎
分布式表引擎,该引擎之所以特殊,在于它其实创建的是一张虚拟表,它是多张本地表组合在一起的逻辑表。
怎么理解呢?就是上面的所有表引擎,在建表时,其实创建的都是本地表(当前机器上的表),但是如果你想要把一份数据集,同时写入到多台机器上,但是又只想通过一个表的入口来实现。
这个Distributed引擎表就是干这个事情的,关于这个表引擎的具体玩法,可参考旧文:
适合场景:数据量巨大,需要将数据合理拆分到多台机器上的场景。
4.2 MaterializedView引擎
叫物化视图引擎,官网对这部分的介绍很简短,几乎是一句带过,但根据我使用过的感受来看,可以把它理解为:架在数据源表跟目标表之间的一个数据管道。
所以,这个物化视图引擎也不存储实际的数据,它的目的就是:通过一定的数据采集规则(筛选,聚合等),将数据源的数据根据该规则,实时地把目标结果给导入到目标中。
所以,这里面你需要确定数据源表,以及目标表。
数据源表:既可以是integration引擎表,也可以任何一张CK已经有数据的表。
目标表:需要创建的,除integration引擎表之外的任何表。
具体的玩法,也可以参考旧文:
适合场景:根据一定取数规则,将数据源表的数据源源不断给导入到目标表的场景。
5. 最后
CK的表引擎种类繁多,而且各种引擎之间还可以配合使用,对于使用者来说,想要把这些功能全都高清楚,且熟练使用,确实不是一件容易的事。
使用难道比较大,也是CK区别于其他数据库的一大特点,但是使用成本高,同时也意味能提供强大的功能,以及覆盖更广的业务范围。
自古都是鱼和熊掌不可兼得,不是吗。
