Clickhouse 的 variant 类型,不能干啥?

来源:安瑞哥是码农


之前在解决 schema-free 的 json 数据存储问题时,就有同学建议用 Doris 的 variant 数据类型,只不过,因为我当前的 Doris 集群部署的是2.0.2版本,而当前版本不支持该类型(需要2.1及以上版本),所以当时只能作罢。


但是最近,看到同样的数据类型,Clickhouse(下称CK) 也是支持的,于是从各自的官网介绍中,都大致了解了彼此对这个 variant 类型的功能介绍。


从功能介绍来说,无论是 CK 还是 Doris,它们的目标都是在解决,对于一个「值类型不确定」的列,怎么样用一种比较合理的方式,把它作为一个数据库字段,给存储起来,以便后续的检索。


Doris 跟 CK 之间的区别


对于 Doris 来说:


虽然它声称可以自动识别写进来的数据类型,但现阶段,它好像更强调用 variant 类型来存储 json 类型的数据。


这样一来,Doris 就会自动把这个 json 内部的 key 以及子 key 都给提取出来,并且以列的方式进行存储(很诧异为什么它的 json type 不是这么干的,多少有点违背常理)。


Doris 定义 variant 类型时,是这样式的:


v VARIANT


而对于 CK 来说:


它就没有刻意去强调要你存储 json 数据,而是各种类型的数据,你都可以往里塞,并且跟 Doris 不同的是,CK 在定义 variant 类型时,必须要定义它可以容纳的子类型


CK 定义 variant 类型时,是这样式的:


v Variant(String, UInt32, Map(String, String))


那么今天这篇文章,让我们先一起走进 CK 的世界,来看看它的 variant 是怎么玩的。



0. 读官网


跟 json type 一样,CK 对于 variant type,目前也只是处于「实验性阶段」,



所以,想要把它用起来,得把这个实验性的开关给打开。


但是,接下来,有件混蛋的事情就出现了,CK 这个官方文档有个特点,或者说缺陷,那就是文档里面所有的功能介绍,它都没有给你区分版本



所以单纯从文档描述来看,你还以为这个 variant 数据类型是 CK 全系都支持的,结果我用23.x版本的一尝试才发现。


既不能打开这个功能的使用开关:


又识别不了这个 variant 类型:



后来一查才发现,尼玛的,这个 variant 是24.x版本之后才引入的,害我折腾半天。


得亏我还有另外一套24.x版本的 CK,要不然,今天到这里就 Game Over 了。 


但,坑爹的还在后面...



1. 设计表


想着把我之前的那份带 json 字段的数据源给写入到 variant 类型,然后看看写入之后,它的查询便利性怎么样。


于是,想着用如下的 SQL 建一张表:


CREATE TABLE variant_with_mergetree_engine(
    `domain` String,
    `detail` Variant(JsonString),
    `create_time` DateTime
)
ENGINE = MergeTree
ORDER BY domain


其中 detail 这个字段就是用来存储 json 的,当然,如果写入的数据不是标准的 json,那理论上,它还可以以 String 的类型进行存储,这个就是 variant 类型需要发挥的作用。


想法很好对不对,但是,它偏不如你的意。


说什么抛出异常是遇到了「动态列」,那哪个是动态列呢?


经过一番折腾之后才搞明白,这个所谓的动态列,指的是 variant 里面的 json type,意思是当前引擎不支持。


好,那咱换一个引擎试试:


CREATE TABLE variant_with_momory_engine
(
    `domain` String,
    `detail` Variant(JsonString),
    `create_time` DateTime
)
ENGINE = MergeTree
ORDER BY domain


咦,建成功了:


2. 写数据


既然换成 Memory 引擎之后,表能建成功,那咱就写数据吧。


这不写不要紧,一写,又尼玛出事了。


无论你是用 insert into ...  select .... 的方式,还是用最傻X的 insert into ... values (...) 的方式。


都给你来同样的这一出:


抛出来的异常,跟上面用 MergeTree 引擎建表时候一毛一样。


说明,对于当前的 CK 来说,甭管是 MergeTree 引擎,还是 Memory 引擎(其他引擎就不试了,意义不大),都不支持 variant 的子类型中,包含 json type


我是咋知道的呢?


试错试出来的喽,你看我把这个 json type 给换成其他的 type 看看:


把 variant 原来的 json 子类型,给换成 map 类型后,就可以建表成功了。


而且,数据写入也没有问题:



写入后的数据量:


 


最后


严格来说,这次对 CK 的 variant 测试,没有到达预期的结果,原因很简单,它不支持子类型出现 json type。


这一点,跟同样支持 variant 的 Doris 恰恰相反。


不过,CK 之所以这么干,我估计是因为人家已经有明确的 json 类型了,而且从之前的测试结论也可以看出来,CK 的 json type,确实是「正儿八经」的(虽然有bug),人家会对其中的 key,以及子 key 做全部的拉平处理,可以作为独立字段进行查询。


而 Doris 的 json type,相比之下就有点闹着玩的味道,难怪它主推用 variant 来解决对 json 数据的查询问题的。


总结一下,这次对 CK 的 Variant 使用结论:


1. 只在24.x版本推出,而且也只是「实验版」;


2. 在使用 variant 的时候,需要明确指定它包含的「子类型」,但是这个子类型里面,不可以有 json type,如果想存储 json,用它专门的 json 类型;


至于 Doris 的 variant 表现如何,咱下次就把它玩起来看看。

请使用浏览器的分享功能分享到微信等