1. 复合类型 除了基础数据类型之外,ClickHouse 还提供了数组、元组、枚举和嵌套等复合类型。这些类型通常 是其他数据库原生不具备的特性。拥有了复合类型之后,ClickHouse 的数据模型有了更强的表达能力。
2. 枚举类型 ClickHouse支持枚举类型,这是一种在定义常量时经常会使用的数据类型。ClickHouse提供了Enum8和Enum16两种枚举类型,它们除了取值范围不同之外,别无二致。
2.1 规则及基本用法
枚举固定使用 ( String : Int ) ( Key / Value) 键值对的形式定义数据
Enum8 用 'String'= Int8 描述,value范围 Int8 的取值范围
Enum16 用 'String'= Int16 描述 ,value范围 Int16 的取值范围
Key 和 Value 是不允许重复的,要保证唯一性
Key和Value的值都不能为Null,但Key允许是空字符串
写入枚举数据的时候,只会用到Key字符串部分
数据在写入的时,会对照枚举集合项的内容逐一检查。如果Key字符串不在集合范围内则会抛出异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 CREATE TABLE enum_test( `x` Nullable(Enum8('hello' = 1 , 'world' = 2 , 'clickhouse' = 3 )) ) ENGINE = TinyLog INSERT INTO enum_test Values ('hello' ),('world' ),(NULL );select * from enum_test;┌─x─────┐ │ hello │ │ world │ │ ᴺᵁᴸᴸ │ └───────┘ INSERT INTO enum_test VALUES ('spark' );Exception on client: Code: 36. DB::Exception: Unknown element 'spark' for enum: data for INSERT was parsed from query Connecting to localhost:9977 as user default. Connected to ClickHouse server version 21.4 .3 revision 54447. CREATE TABLE enum_test2 (x Enum8(1 = 'a' , 2 = 'b' )) ENGINE = TinyLog;Received exception from server (version 21.4 .3 ): Code: 223. DB::Exception: Received from localhost:9977. DB::Exception: Elements of Enum data type must be of form: 'name' = number, where name is string literal and number is an integer.
2.2 查询对应行的数值 1 2 3 4 5 6 7 8 9 SELECT CAST (x, 'Int8' ) FROM enum_test;┌─CAST (x, 'Int8' )─┐ │ 1 │ │ 2 │ └─────────────────┘
2.3 查询中创建枚举值 1 2 3 4 5 6 7 8 9 10 SELECT CAST ('a' , 'Enum8(\' a\' = 1, \' b\' = 2)' ) AS en, CAST (en, 'Int8' ) AS enInt, toTypeName(en) AS entype; ┌─en─┬─enInt─┬─entype──────────────────┐ │ a │ 1 │ Enum8('a' = 1 , 'b' = 2 ) │ └────┴───────┴─────────────────────────┘
2.4 总结
Enum 类型以二进制读取和写入的方式与 Int8 和 Int16 类型一样的。
当以文本方式读取的时候,ClickHouse 将 值 解析成字符串然后去枚举值的集合中搜索对应字符串。如果没有找到,会抛出异常。
当读取文本格式的时候,会根据读取到的字符串去找对应的数值。如果没有找到,会抛出异常。
当以文本形式写入时,ClickHouse 将值解析成字符串写入。如果列数据包含垃圾数据,则抛出异常。
在 ORDER BY,GROUP BY,IN,DISTINCT 等等中,Enum 的行为与相应的数字相同。例如,按数字排序。对于等式运算符和比较运算符,Enum 的工作机制与它们在底层数值上的工作机制相同。
枚举值不能与数字进行比较。枚举可以与常量字符串进行比较。如果与之比较的字符串不是有效Enum值,则将引发异常。可以使用 IN 运算符来判断一个 Enum 是否存在于某个 Enum 集合中,其中集合中的 Enum 需要用字符串表示。
大多数具有数字和字符串的运算并不适用于Enums;例如,Enum 类型不能和一个数值相加。但是,Enum有一个原生的 toString 函数,它返回它的字符串值。
Enum 值使用 toT 函数可以转换成数值类型,其中 T 是一个数值类型。若 T 恰好对应 Enum 的底层数值类型,这个转换是零消耗的。
Enum 类型可以被 ALTER 无成本地修改对应集合的值。可以通过 ALTER 操作来增加或删除 Enum 的成员。作为安全保障,改变之前使用过的 Enum 成员将抛出异常。
通过 ALTER 操作,可以将 Enum8 转成 Enum16,反之亦然,就像 Int8 转 Int16一样。
3. 数组
数组是由 T 类型的0 到多个同元素组成,T 可以是任意类型,包含数组类型,数组内可以包含多个类型,但各个类型间必须兼容
但不推荐使用多维数组,ClickHouse 对多维数组的支持有限。例如,不能存储在 MergeTree 表中存储多维数组。
创建数组可以使用array函数,如array(T)
创建数组也可以使用[],如[1,2,3]
查询时无需指定数组元素类型,可以自己推断数据类型,并使用最小可表达的数据类型
3.1 使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SELECT [1 , 2 ] AS x, toTypeName(x); ┌─x─────┬─toTypeName(array (1 , 2 ))─┐ │ [1 ,2 ] │ Array (UInt8) │ └───────┴─────────────────────────┘ SELECT [1 , 2 ] AS x, toTypeName(x) AS type; ┌─x─────┬─type─────────┐ │ [1 ,2 ] │ Array (UInt8) │ └───────┴──────────────┘
3.2 在数据表中使用 Array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 CREATE TABLE array_test( `a` Array (Int8) ) ENGINE = TinyLog insert into table array_test values (array (1 ,2 ,3 ));select * from array_test;┌─a───────┐ │ [1 ,2 ,3 ] │ └─────────┘ insert into table array_test values (array ());select * from array_test;┌─a───────┐ │ [1 ,2 ,3 ] │ │ [] │ └─────────┘
3.3 类型检测
ClickHouse 会自动检测数组元素,并根据元素计算出存储这些元素最小的数据类型。
如果在元素中存在 Null 或存在 Nullable 类型元素,那么数组的元素类型将会变成 Nullable 。
如果 ClickHouse 无法确定数据类型,它将产生异常。
1 2 3 4 5 6 SELECT array (1 , 2 , NULL ) AS x, toTypeName(x);┌─x──────────┬─toTypeName(array (1 , 2 , NULL ))─┐ │ [1 ,2 ,NULL ] │ Array (Nullable(UInt8)) │ └────────────┴───────────────────────────────┘
如果您尝试创建不兼容的数据类型数组,ClickHouse 将引发异常:
1 2 3 4 5 6 7 8 9 insert into table array_test values (array ('a' ));Exception on client: Code: 6. DB::Exception: Cannot parse string 'a' as Int8: syntax error at begin of string. Note: there are toInt8OrZero and toInt8OrNull functions, which returns zero/ NULL instead of throwing exception.: while executing 'FUNCTION CAST(assumeNotNull(array(_dummy_0)) :: 3, ' Array (Int8)' :: 1) -> CAST(assumeNotNull(array(_dummy_0)), ' Array (Int8)') Array(Int8) : 2' : data for INSERT was parsed from query Connecting to localhost:9977 as user default. Connected to ClickHouse server version 21.4 .3 revision 54447.
4. 元组
元组类型由1~n个元素组成,每个元素之间允许设置不同的数据类型,且彼此之间不要求兼容。
元组同样支持类型推断,其推断依据仍然以最小存储代价为原则。
元组也可以使用两种方式定义,常规方式tuple(T)
方式一:tuple(T1,T2,…),常规方式
方式二:(T1,T2,…)
元素类型和泛型的作用类似,可以进一步保障数据质量。在数据写入的过程中会进行类型检查。
4.1 使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 SELECT tuple(1 ,'a' ) AS x, toTypeName(x) as type;┌─x───────┬─type─────────────────┐ │ (1 ,'a' ) │ Tuple(UInt8, String) │ └─────────┴──────────────────────┘ SELECT tuple(1 ,'a' ) AS x, toTypeName(x) as type, x.1 as v1, x.2 as v2;┌─x───────┬─type─────────────────┬─v1─┬─v2─┐ │ (1 ,'a' ) │ Tuple(UInt8, String) │ 1 │ a │ └─────────┴──────────────────────┴────┴────┘
4.2 在数据表中使用元组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 CREATE TABLE tuple_table( `t` Tuple(Int8, String, Array (String), Array (Int8)) ) ENGINE = TinyLog INSERT INTO tuple_table VALUES ((1 , 'a' , ['a' , 'b' , 'c' ], [1 , 2 , 3 ]));INSERT INTO tuple_table VALUES (tuple(11 , 'A' , ['A' , 'B' , 'C' ], [11 , 22 , 33 ]));SELECT t, t.2 , t.3 , t.4 FROM tuple_table;┌─t─────────────────────────────────┬─tupleElement(t, 2 )─┬─tupleElement(t, 3 )─┬─tupleElement(t, 4 )─┐ │ (1 ,'a' ,['a' ,'b' ,'c' ],[1 ,2 ,3 ]) │ a │ ['a' ,'b' ,'c' ] │ [1 ,2 ,3 ] │ │ (11 ,'A' ,['A' ,'B' ,'C' ],[11 ,22 ,33 ]) │ A │ ['A' ,'B' ,'C' ] │ [11 ,22 ,33 ] │ └───────────────────────────────────┴────────────────────┴────────────────────┴────────────────────┘ INSERT INTO tuple_table VALUES ((101 , 'hello' , 'world' , [1 , 2 , 3 ]));
5. 嵌套类型
嵌套类型,顾名思义是一种嵌套表结构
数据表,可以定义任意多个嵌套类型字段
每个字段的嵌套层级只支持一级,即嵌套表内不能继续使用嵌套类型
简单场景的层级关系或关联关系,使用嵌套类型能够非常方便的存储对应的数据
嵌套的数据定义方式为:Nested(Name1 Type1,Name2 Type2,…)就像一个嵌套的表。
嵌套数据结构的参数 - 列名和类型 - 与在CREATE查询中的指定方式相同
5.1 使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 CREATE TABLE nest_table( `name` String, `age` Int8, `dept` Nested(id UInt8, name String) ) ENGINE = TinyLog insert into nest_table values ('xiaohong' , 18 , [1 ], ['财务部' ]), ('codes' , 18 , [1 ,2 ,3 ],['hadoop' ,'spark' ,'flink' ]); select * from nest_table;┌─name─────┬─age─┬─dept.id─┬─dept.name──────────────────┐ │ xiaohong │ 18 │ [1 ] │ ['财务部' ] │ │ codes │ 18 │ [1 ,2 ,3 ] │ ['hadoop' ,'spark' ,'flink' ] │ └──────────┴─────┴─────────┴────────────────────────────┘
通过插入数据信息显示,异常显示需要 Array ,而不是单纯的 Int 。
可以看出嵌套类型本质是一个多维数组的结构。
嵌套类型的一个字段对应一个数组。字段对应的数组内的数量没有限制,但是字段之间需要数组内的数量对齐。
在Hive中,有一种复杂类型叫做 Struct,跟当前这种情况很类似,但是根据经验,推荐尽量少使用 Nested 类型
6 Nullable(TypeName)
Nullable 并不能算是一种独立的数据类型,更像是一种修饰符,需要与基础数据类型一起搭配使用
Nullable 类型与 Java8 的 Optional 对象有些相似,它表示某个基础数据类型可以是Null 值
特殊标记 (NULL) 表示 “缺失值”,可以与 TypeName 的正常值存放一起。例如,Nullable(Int8) 类型的列可以存储 Int8 类型值,而没有值的行将存储 NULL。
Nullable 只能和基本类型搭配使用
不能使用在 Array/Tuple 这种复合类型上
不能作为索引字段【Order by()】
慎用 Nullable ,写入写出性能不好。
在正常情况下,每个列字段的数据会被存储在对应的 [Column].bin文件中。当列字段被Nullable 类型修饰后,会额外生成一个 [Column].null.bin 文件专门保存它的 Null 值。这意味着在读取和写入数据时,需要一倍的额外文件操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 CREATE TABLE null_test( `c1` String, `c2` Nullable(UInt8) ) ENGINE = TinyLog insert into null_test values ('aa' , null ),('bb' , 99 );select c1, c2 from null_test;┌─c1─┬───c2─┐ │ aa │ ᴺᵁᴸᴸ │ │ bb │ 99 │ └────┴──────┘
7. Nothing 此数据类型的唯一目的是表示不是期望值的情况。 所以不能创建一个 Nothing 类型的值。
例如,文本 NULL 的类型为 Nullable(Nothing)。详情请见 Nullable
Nothing 类型也可以用来表示空数组:
1 2 3 4 5 6 SELECT toTypeName(array ()) as type;┌─type───────────┐ │ Array (Nothing) │ └────────────────┘
8. Domain
Domain类型是特定实现的类型,它总是与某个现存的基础类型保持二进制兼容的同时添加一些额外的特性,以能够在维持磁盘数据不变的情况下使用这些额外的特性。
目前ClickHouse暂不支持自定义domain类型。
域名类型分为 IPv4 和 IPv6 两类,本质上它们是对整型和字符串的进一步封装。
IPv4 类型是基于UInt32 封装的
IPv6 类型是基于FixedString(16) 封装的
如果你可以在一个地方使用与Domain类型二进制兼容的基础类型,那么在相同的地方您也可以使用Domain类型,例如:
使用Domain类型作为表中列的类型
对Domain类型的列进行读/写数据
如果与Domain二进制兼容的基础类型可以作为索引,那么Domain类型也可以作为索引
将Domain类型作为参数传递给函数使用
8.1 Domains的额外特性
在执行SHOW CREATE TABLE 或 DESCRIBE TABLE时,其对应的列总是展示为Domain类型的名称
在INSERT INTO domain_table(domain_column) VALUES(…)中输入数据总是以更人性化的格式进行输入
在SELECT domain_column FROM domain_table中数据总是以更人性化的格式输出
在INSERT INTO domain_table FORMAT CSV …中,实现外部源数据以更人性化的格式载入
8.2 Domains类型的限制
无法通过ALTER TABLE将基础类型的索引转换为Domain类型的索引。
当从其他列或表插入数据时,无法将string类型的值隐式地转换为Domain类型的值。
无法对存储为Domain类型的值添加约束。
8.3 IPv4 IPv4是与UInt32类型保持二进制兼容的Domain类型,其用于存储IPv4地址的值。它提供了更为紧凑的二进制存储的同时支持识别可读性更加友好的输入输出格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 CREATE TABLE ip4_test( `url` String, `ip` IPv4 ) ENGINE = Memory describe ip4_test;┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ │ url │ String │ │ │ │ │ │ │ ip │ IPv4 │ │ │ │ │ │ └──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘ insert into ip4_test values ('www.baidu.com' , '192.168.22.55' );select url, ip, toTypeName(ip) from ip4_test;┌─url───────────┬─ip────────────┬─toTypeName(ip)─┐ │ www.baidu.com │ 192.168 .22 .55 │ IPv4 │ └───────────────┴───────────────┴────────────────┘ SELECT url,toTypeName(ip) as type, hex(ip) FROM ip4_test;┌─url───────────┬─type─┬─hex(ip)──┐ │ www.baidu.com │ IPv4 │ C0A81637 │ └───────────────┴──────┴──────────┘ SELECT toTypeName(ip) as type, CAST (ip as UInt32) as i FROM ip4_test;┌─type─┬──────────i─┐ │ IPv4 │ 3232241207 │ └──────┴────────────┘ SELECT IPv4NumToString(ip) as s, toTypeName(s) as type FROM ip4_test;┌─s─────────────┬─type───┐ │ 192.168 .22 .55 │ String │ └───────────────┴────────┘
为什么不直接使用字符串来代替 IPv4 类型呢 ? 1、出于便捷性的考量,例如IPv4类型支持格式检查,格式错误的IP数据是无法被写入的 2、出于性能的考量,同样以IPv4为例,IPv4使用UInt32存储,相比String更加紧凑,占用的空间更小, 查询性能更快。IPv6类型是基于FixedString(16)封装的,它的使用方法与IPv4基本相同。
在使用Domain类型的时候还有一点需要注意,虽然它从表象上看起来与String一样,但Domain类型并 不是字符串,所以它不支持隐式的自动类型转换。如果需要返回IP的字符串形式,则需要显式调用 IPv4NumToString或IPv6NumToString函数进行转换。
8.4 IPv6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 CREATE TABLE ip6_test( `url` String, `ip` IPv6 ) ENGINE = Memory; describe ip6_test;┌─name─┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ │ url │ String │ │ │ │ │ │ │ ip │ IPv6 │ │ │ │ │ │ └──────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘ INSERT INTO ip6_test (url, ip) VALUES ('https://clickhouse.tech' , '2001:44c8:129:2632:33:0:252:2' );SELECT * FROM ip6_test;┌─url─────────────────────┬─ip────────────────────────────┐ │ https:/ / clickhouse.tech │ 2001 :44 c8:129 :2632 :33 :0 :252 :2 │ └─────────────────────────┴───────────────────────────────┘ SELECT toTypeName(ip) as type, hex(ip) FROM ip6_test;┌─type─┬─hex(ip)──────────────────────────┐ │ IPv6 │ 200144 C8012926320033000002520002 │ └──────┴──────────────────────────────────┘ SELECT IPv6NumToString(ip) as s, toTypeName(s) as type FROM ip6_test;┌─s─────────────────────────────┬─type───┐ │ 2001 :44 c8:129 :2632 :33 :0 :252 :2 │ String │ └───────────────────────────────┴────────┘ SELECT CAST (ip as FixedString(16 )) as i,toTypeName(i) as type FROM ip6_test;┌─i───────┬─type────────────┐ │ D�)& 23 R │ FixedString(16 ) │ └─────────┴─────────────────┘
9. LowCardinality
LowCardinality 是一种改变数据存储和数据处理方法的概念。
ClickHouse会把 LowCardinality 所在的列转为字典编码类型,在大多数情况下处理字典编码的数据可以显著的增加SELECT 查询速度。
如果一个字典包含少于10000个不同的值,那么ClickHouse可以进行更高效的数据存储和处理。反之如果字典多于10000,效率会表现的更差。
当使用字符类型的时候,可以考虑使用 LowCardinality 代替 Enum
用法:LowCardinality(data_type)
9.1 代码示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 CREATE TABLE low_cardinality_test( `id` UInt16, `strings` LowCardinality(String) ) ENGINE = Memory describe low_cardinality_test;┌─name────┬─type───────────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ │ id │ UInt16 │ │ │ │ │ │ │ strings │ LowCardinality(String) │ │ │ │ │ │ └─────────┴────────────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘ insert into low_cardinality_test values (1 ,'hello' ),(2 ,'clickhouse' );select * from low_cardinality_test;┌─id─┬─strings────┐ │ 1 │ hello │ │ 2 │ clickhouse │ └────┴────────────┘
9.2 相关的设置 9.2.1 allow_suspicious_low_cardinality_types 允许或限制将 LowCardinality 用于固定大小为8个字节或更少的数据类型:数字数据类型和 FixedString(8_bytes_or_less)。
对于小的固定值,LowCardinality 通常使用of效率低下,因为ClickHouse为每行存储一个数字索引。因此:
磁盘空间使用量可能会增加。
RAM消耗可能更高,具体取决于字典的大小。
由于额外的编码/编码操作,某些功能的工作速度可能较慢。
由于上述所有原因,MergeTree -engine 表中的合并时间可能会增加。
可能的值:
1-的使用LowCardinality不受限制。
0-的使用LowCardinality受到限制。
默认值:0。
9.2.2 low_cardinality_max_dictionary_size 在可写入存储文件系统的 LowCardinality 数据类型的共享全局词典的行中设置最大大小。在无限制的字典增长的情况下,此设置可以防止RAM出现问题。由于最大字典大小限制,所有无法编码的数据都是ClickHouse用普通方法写入的。
可能的值:
预设值:8192。
9.2.3 low_cardinality_use_single_dictionary_for_part 使用单个字典打开或关闭数据部分。
默认情况下,ClickHouse服务器监视词典的大小,如果词典溢出,则服务器将开始编写下一个词典。禁止创建多个字典集low_cardinality_use_single_dictionary_for_part = 1。
可能的值:
1-禁止为数据部分创建多个词典。
0-禁止为数据部分创建多个词典。
默认值:0。
允许或限制将 LowCardinality 数据类型与本机格式一起使用。
如果对的使用 LowCardinality 受到限制,则ClickHouse服务器会将-列转换为普通列以 LowCardinality 进行 SELECT 查询,并将普通列转换为-列 LowCardinality 进行 INSERT 查询。
主要对于不支持 LowCardinality 数据类型的第三方客户端,此设置是必需的。
可能的值:
1-的使用 LowCardinality 不受限制。
0-的使用 LowCardinality 受到限制。
默认值:1。
9.3 函数
10. 聚合函数类型 10.1 AggregateFunction
AggregateFunction — 参数化的数据类型。
定义方式:AggregateFunction(name, types_of_arguments…)
定义参数:
写入数据时,需要调用相应的State函数,可以通过聚合函数名称加-State后缀的形式得到它。
查询数据时,需要调用相应的Merge函数,相同的聚合函数名加-Merge后缀的形式来得到。
不使用Merge函数查询数据时将会是无法显示的二进制。
使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 CREATE TABLE aggregate_function_test( id String, code AggregateFunction(uniq,String), value AggregateFunction(sum,UInt32) ) ENGINE = Memory; INSERT INTO TABLE aggregate_function_test SELECT '001' , uniqState('code1' ), sumState(toUInt32(100 ));INSERT INTO TABLE aggregate_function_test SELECT '001' , uniqState('code1' ), sumState(toUInt32(150 )); INSERT INTO TABLE aggregate_function_test SELECT '002' , uniqState('code1' ), sumState(toUInt32(100 ));INSERT INTO TABLE aggregate_function_test SELECT '002' , uniqState('code2' ), sumState(toUInt32(50 )); SELECT id,uniqMerge(code),sumMerge(value ) FROM aggregate_function_test GROUP BY id; ┌─id──┬─uniqMerge(code)─┬─sumMerge(value )─┐ │ 002 │ 2 │ 150 │ │ 001 │ 1 │ 250 │ └─────┴─────────────────┴─────────────────┘ SELECT id, code, value FROM aggregate_function_test;┌─id──┬─code─┬─value ─┐ │ 001 │ n� │ d │ └─────┴──────┴───────┘ ┌─id──┬─code─┬─value ─┐ │ 001 │ n� │ � │ └─────┴──────┴───────┘ ┌─id──┬─code─┬─value ─┐ │ 002 │ ߙc� │ 2 │ └─────┴──────┴───────┘ ┌─id──┬─code─┬─value ─┐ │ 002 │ n� │ d │ └─────┴──────┴───────┘
10.2 SimpleAggregateFunction SimpleAggregateFunction(name, types_of_arguments…) 数据类型存储聚合函数的当前值, 并不像 AggregateFunction 那样存储其全部状态。这种优化可以应用于具有以下属性函数: 将函数 f 应用于行集合 S1 UNION ALL S2 的结果,可以通过将 f 分别应用于行集合的部分, 然后再将 f 应用于结果来获得: f(S1 UNION ALL S2) = f(f(S1) UNION ALL f(S2))。 这个属性保证了部分聚合结果足以计算出合并的结果,所以我们不必存储和处理任何额外的数据。
SimpleAggregateFunction(func, Type) 的值外观和存储方式于 Type 相同, 所以你不需要应用带有 -Merge/-State 后缀的函数。
SimpleAggregateFunction 的性能优于具有相同聚合函数的 AggregateFunction 。
参数
10.2.1 测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 drop table simpleAggregate_function_test;CREATE TABLE simpleAggregate_function_test( id String, code SimpleAggregateFunction(max,String), value SimpleAggregateFunction(sum,UInt64) ) ENGINE = Memory; INSERT INTO TABLE simpleAggregate_function_test values ('001' ,'code1' ,100 ),('001' ,'code1' ,150 ); INSERT INTO TABLE simpleAggregate_function_test values ('002' ,'code1' ,100 ),('002' ,'code2' ,50 ); SELECT id,max (code),sum (value ) FROM simpleAggregate_function_test GROUP BY id; ┌─id──┬─uniqMerge(code)─┬─sumMerge(value )─┐ │ 002 │ 2 │ 150 │ │ 001 │ 1 │ 250 │ └─────┴─────────────────┴─────────────────┘ SELECT id, code, value FROM simpleAggregate_function_test┌─id──┬─code──┬─value ─┐ │ 002 │ code1 │ 100 │ │ 002 │ code2 │ 50 │ └─────┴───────┴───────┘ ┌─id──┬─code──┬─value ─┐ │ 001 │ code1 │ 100 │ │ 001 │ code1 │ 150 │ └─────┴───────┴───────┘
10.2.2 支持的聚合函数
any
anyLast
min
max
sum
sumWithOverflow
groupBitAnd
groupBitOr
groupBitXor
groupArrayArray
groupUniqArrayArray
sumMap
minMap
maxMap
argMin
argMax
11.Map
Map(key, value)数据类型存储key:value对
Map数据类型仍在开发阶段。要使用它,必须进行设置 allow_experimental_map_type = 1。
参数 -—key对中的关键部分。字符串或整数 -—value对的值部分。字符串,整数或数组
11.1 测试代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 set allow_experimental_map_type = 1 ;CREATE TABLE map_test (a Map(String, UInt64)) ENGINE= Memory;INSERT INTO map_test VALUES ({'key1' :1 , 'key2' :10 }), ({'key1' :2 ,'key2' :20 }), ({'key1' :3 ,'key2' :30 });select * from map_test;┌─a────────────────────┐ │ {'key1' :1 ,'key2' :10 } │ │ {'key1' :2 ,'key2' :20 } │ │ {'key1' :3 ,'key2' :30 } │ └──────────────────────┘ SELECT a['key2' ] as value FROM map_test;┌─value ─┐ │ 10 │ │ 20 │ │ 30 │ └───────┘
如果key该Map()列中没有此类内容,则查询将为数字值,空字符串或空数组返回零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 INSERT INTO map_test VALUES ({'key3' :100 }), ({});SELECT a['key3' ] FROM map_test;┌─arrayElement(a, 'key3' )─┐ │ 0 │ │ 0 │ │ 0 │ └─────────────────────────┘ ┌─arrayElement(a, 'key3' )─┐ │ 100 │ │ 0 │ └─────────────────────────┘
11.2 将元组转换为地图类型 你可以投Tuple()作为Map()使用CAST 功能:
1 2 3 4 5 6 SELECT CAST (([1 , 2 , 3 ], ['Ready' , 'Steady' , 'Go' ]), 'Map(UInt8, String)' ) AS map , toTypeName(map) as type;┌─map───────────────────────────┬─type──────────────┐ │ {1 :'Ready' ,2 :'Steady' ,3 :'Go' } │ Map(UInt8,String) │ └───────────────────────────────┴───────────────────┘