ClickHouse 实战:ClickHouse 高级数据类型极简教程
Posted 东海陈光剑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ClickHouse 实战:ClickHouse 高级数据类型极简教程相关的知识,希望对你有一定的参考价值。
1. ClickHouse高级数据类型
在上一章节中我们主要介绍了 ClickHouse 基础数据类型。
“数据类型”是编程的酵母,若是少了它,程序难以被计算机“消化”。数据类型是每一种语言都需要掌握的。我们通过“数据类型”走进丰富的程序世界。ClickHouse 中除了基础数据类型之外,还提供了数组、元组、枚举和嵌套类型,总共四种复合类型。另外,我们还可以使用聚合函数类型动态自定义类型,比如说 Bitmap 类型。这些类型通常都是其他数据库原生不具备的特性,拥有了复合类型之后,ClickHouse 的数据模型表达能力就更强了。另外,ClickHouse 还提供了丰富的函数,以实现编程级的SQL 功能。本章就来详细介绍 ClickHouse 高级数据类型。在下一章中,介绍常用函数的使用。
1.1. Array数组类型
在计算机科学中,最早的数据类型只有整数和浮点数类型,用来区分这两种数字的计算,如在 Fortran(Formula Translation,意为“公式翻译”。由约翰·巴克斯1954 年提出) 语言中。后来到了 1960 年代,数据类型中又多了结构体和记录数组。在 1970 年代,引入了几个更丰富的概念:抽象数据类型,多态泛型,模块系统和子类型等。
数组类型是最常用、最普遍的数据类型,几乎在所有程序设计语言中都支持。本节就来介绍 ClickHouse 中的数组类型。
1.1.1. 数组类型定义
数组Array(T) 是有序的元素序列,用于储存多个相同数据类型T的集合。
数组的特点:
1.数组是相同数据类型的元素的集合。
2.数组中的各元素的存储是有先后顺序的,它们在内存中按照这个先后顺序连续存放在一起。
3.数组元素用整个数组的名字和它自己在数组中的顺序位置来表示。
一般编程语言中,下标都是从 0 开始。例如,a[0]表示名字为a的数组中的第一个元素,a[1]代表数组a的第二个元素,以此类推。但是,需要特别注意的是,在 ClickHouse 中数组下标从 1 开始。也就是第一个元素是 a[1]。
1.1.2. 创建数组
创建数组
我们可以使用 array(T) 或者 [ T ] 创建一个数组。
SQL 实例:
select array(1,2,3) as a1, [4,5,6] as a2 Format Vertical
输出:
a1: [1,2,3]
a2: [4,5,6]
数组中的数据类型
当数组中的元素都不为空,数组类型就是不可空的。
SQL 实例:
SELECT
[1, 2, 3] AS a,
toTypeName(a)
FORMAT Vertical
输出:
a: [1,2,3]
toTypeName(array(1, 2, 3)): Array(UInt8)
如果数组中元素有一个NULL空值,类型会相应地变成可空元素类型。
SQL 实例:
SELECT
[1, 2, NULL] AS x,
toTypeName(x)
FORMAT Vertical
输出:
x: [1,2,NULL]
toTypeName(array(1, 2, NULL)): Array(Nullable(UInt8))
如果创建了不兼容的数据类型数组,ClickHouse 将引发异常:
:) select [1,'a']
Received exception from server (version 21.12.1):
Code: 386. DB::Exception: Received from localhost:9000. DB::Exception: There is no supertype for types UInt8, String because some of them are String/FixedString and some of them are not: While processing [1, 'a']. (NO_COMMON_TYPE)
1.1.3. 数组基础操作
判断数组是否为空
函数:empty(array)
功能:判断数组 array 是否为空。
返回值:1:空,0:非空(UInt8类型)。
SQL 实例:
SELECT
empty([]) AS isEmpty,
empty([1]) AS notEmpty
FORMAT Vertical
输出:
isEmpty: 1
notEmpty: 0
还有一个 notEmpty()函数,逻辑相反,此处不赘述。
计算数组长度
函数:length(array)
功能:计算数组元素个数。
返回值:数组长度,类型为UInt64。空数组返回 0,NULL 值返回 NULL。该函数同样适用于计算 String 字符串的长度。
SQL 实例:
SELECT
length([1, 2, 3]) AS a1,
length([]) AS a2,
length(NULL) AS a3
FORMAT Vertical
输出:
a1: 3
a2: 0
a3: ᴺᵁᴸᴸ
获取数组元素
直接使用 a[i] 下标访问数组元素,需要注意的是,i 是从 1 开始,也就是说,数组 a 中第一个元素是 a[1]。
实例 SQL:
SELECT
[1, 2, 3] AS x, --- 等价于array(1,2,3)
toTypeName(x),
length(x) AS size,
x[0] AS x0, ---错误用法,ClickHouse 数组元素下标是从 1 开始的
x[1] AS x1,
x[2] AS x2,
x[3] AS x3
FORMAT Vertical
输出:
x: [1,2,3]
toTypeName(array(1, 2, 3)): Array(UInt8)
size: 3
x0: 0
x1: 1
x2: 2
x3: 3
ClickHouse 以最小存储代价为原则,进行类型推断。所以,我们看到上面的 array(1, 2, 3) 的类型是Array(UInt8)。
判断某个元素是否存在
函数:has(arr, x)
功能说明:判断元素 x 是否在数组 arr 中存在。
返回值:1: 存在, 0: 不存在。
SQL实例:
SELECT has([1, 2, 3], 1) AS hasIt
输出:
┌─hasIt─┐
│ 1 │
└─────┘
数组切片
函数:arraySlice(array, offset[, length])
参数功能说明:
array:数组.
offset:标偏移量。正数表示从左数,负数表示从右数。记住,ClickHouse 中数组的下标是从 1 开始的。
length: 切片长度。不填,默认就是从偏移量到最后一个元素。
返回值:返回一个子数组。
SQL 实例:
SELECT
arraySlice([10, 20, 30, 40, 50], 1, 2) AS res1,
arraySlice([10, 20, 30, 40, 50], 1) AS res2
FORMAT Vertical
输出:
res1: [10,20]
res2: [10,20,30,40,50]
数组元素展开
函数:arrayJoin(arr)
功能说明:使用arrayJoin(arr)函数,可以把数组arr中的每一个元素,展开到多行(unfold)。具体讲,就是 arrayJoin(arr) 函数以Array类型数据arr作为输入,然后对数组中的数据进行迭代,返回多行结果,一行一个数组元素值。简单说,就是“行转列”,把一个数组“炸开”到一列中的多行中去。跟 Hive 中的 explode() 函数功能类似。这么说有点抽象,直接用下面的例子来说明。
SQL 实例:
SELECT
arrayJoin([1, 2, 3] AS src) AS element,
src,
'a'
输出:
┌─element┬─src─┬─'a'─┐
│ 1 │ [1,2,3] │ a │
│ 2 │ [1,2,3] │ a │
│ 3 │ [1,2,3] │ a │
└─────┴─────┴───┘
数组元素去重
函数:arrayDistinct(arr)
功能说明:从数组中删除所有重复的元素。
返回值: 删除所有重复元素之后的子数组。
SQL 实例:
SELECT arrayDistinct([1, 1, nan, nan, 2, 3, 3, 3, NULL, NULL, 3, 4, 5, 6, 6, 6]) AS c
FORMAT Vertical
输出:
c: [1,nan,2,3,4,5,6]
删除连续重复元素
函数:arrayCompact(arr)
功能说明:从数组中删除连续重复的元素。结果值的顺序由源数组中的顺序决定。
返回值: 删除掉连续重复元素之后的子数组。
SQL 实例:
SELECT arrayCompact([1, 1, nan, nan, 2, 3, 3, 3, NULL, NULL, 3, 4, 5, 6, 6, 6]) AS c
FORMAT Vertical
输出:
c: [1,nan,2,3,NULL,3,4,5,6]
连接多个数组
函数:arrayConcat(arr1,arr2,...)
功能说明:连接多个数组为一个数组。
返回值:连接之后的数组(不会去重)。
SQL 实例:
SELECT arrayConcat([1, 2], [3, 4], [5, 6, 2, 3]) AS res
输出:
┌─res───────────────┐
│ [1,2,3,4,5,6,2,3] │
└──────────────────┘
如果想要去重,可以嵌套使用arrayDistinct()函数,如下所示。
SQL 实例:
SELECT arrayDistinct(arrayConcat([1, 2], [3, 4], [5, 6, 2, 3])) AS res
输出:
┌─res───────────┐
│ [1,2,3,4,5,6] │
└──────────────┘
数组倒序
函数:arrayReverse(arr)
功能说明:数组逆序。
返回值:输入数组元素逆序之后的新数组。
SQL 实例:
SELECT arrayReverse([1, 2, 3])
FORMAT Vertical
输出:
arrayReverse([1, 2, 3]): [3,2,1]
数组拍平
函数: arrayFlatten(arr1,arr2,...)
功能说明:将多维数组元素拍平到一个一维数组。适用于任何深度的嵌套数组。一维数组拍平还是一维数组。
返回值:拍平之后一维数组,包含所有源数组的所有元素。
SQL 实例:
SELECT
arrayFlatten([[[1]], [[2], [3, 4, 5]]] AS src) AS flatArr,
src
FORMAT Vertical
输出:
flatArr: [1,2,3,4,5]
src: [[[1]],[[2],[3,4,5]]]
数组元素映射
函数:arrayMap(func, arr1, …)
功能说明:对数组 arr1中的每个元素应用函数 func 计算成新值,然后返回一个新数组。
返回值:新值数组。
SQL 实例:
SELECT arrayMap(x -> (x * x), [1, 2, 3]) AS res
FORMAT Vertical
输出:
res: [1,4,9]
需要注意的是,arrayMap()是一个高阶函数,lambda函数是一个必传参数。
数组元素过滤
函数:arrayFilter(func, arr1,...)
功能说明:根据谓词判断函数 func,过滤出满足条件的数组arr1 中的元素。
返回值:满足条件的子数组。如果没有元素满足条件,返回空数组[]。
SQL 实例:
SELECT arrayFilter(x -> ((x % 2) = 0), [1, 2, 3, 4, 5, 6]) AS res
FORMAT Vertical
输出:
res: [2,4,6]
SQL 实例:
SELECT arrayFilter(x -> (x > 10), [1, 2, 3, 4, 5, 6]) AS res
FORMAT Vertical
输出:
res: []
数组聚合分析
函数:arrayReduce(agg_func, arr1, arr2, ..., arrN)
功能说明:将聚合函数agg_func应用于数组元素并返回其结果。聚合函数的名称以单引号'max'、'sum' 的形式作为字符串传递。当使用带参数的聚合函数时,参数放到括号里,例如 'uniqCombined(17)'。
返回值:聚合结果值,类型为UInt64。
SQL 实例:
SELECT arrayReduce('uniq', [1, 1, 2, 2, 3, 4, 5, 6, 6, 7])
输出: 7
SQL 实例:
SELECT
arrayReduce('uniqCombined(17)', [1, 1, 2, 2, 3, 4, 5, 6, 6, 7]) AS res,
toTypeName(res) AS t
FORMAT Vertical
输出:
res: 7
t: UInt64
计算数组交集
函数:arrayIntersect(arr1,arr2,...)
功能说明:计算 arr1,arr2等数组元素交集。
返回值:交集元素子数组,结果去重。
SQL 实例:
SELECT arrayIntersect([1, 2, 3, 3], [4, 5, 6]) AS noIntersect,
arrayIntersect([1, 2, 3, 3], [2, 2, 3, 4, 5, 6]) AS hasIntersect
FORMAT Vertical
输出:
noIntersect: []
hasIntersect: [3,2]
计算数组并集
组合使用函数来实现arrayDistinct(arrayConcat(a, b))。
SQL 实例:
SELECT
[1, 2] AS a,
[2, 3] AS b,
arrayDistinct(arrayConcat(a, b)) AS res
FORMAT Vertical
输出:
a: [1,2]
b: [2,3]
res: [1,2,3]
计算数组差集
差集的实现要有一些技术含量了(感觉 ClickHouse 后面应该内置数组差集计算函数,实现类似arrayExcept() 函数),需要使用数组交集函数arrayIntersect() 结合高阶函数 arrayMap()和 arrayFilter()来组合实现。
SQL 实例:
SELECT
arrayIntersect([1, 2, 3], [4, 5, 6]) AS noIntersect,
arrayIntersect([1, 2, 3], [2, 3, 4, 5, 6]) AS hasIntersect
FORMAT Vertical
SELECT
[1, 2] AS a,
[2, 3] AS b,
arrayFilter(x -> (x IS NOT NULL), arrayMap(x -> multiIf(x NOT IN arrayIntersect(a, b), x, NULL), a)) AS res
FORMAT Vertical
输出:
a: [1,2]
b: [2,3]
res: [1]
另外, ClickHouse 中有集合交(INTERSECT)、并(UNION)、差(EXCEPT)的SQL子句关键字,可以实现数组的交并差运算。实例 SQL 如下。
交集SQL
SELECT a.i
FROM
(
SELECT arrayJoin([1, 2]) AS i
) AS a
INTERSECT
SELECT b.i
FROM
(
SELECT arrayJoin([2, 3]) AS i
) AS b
输出:2
并集 SQL
SET union_default_mode = 'ALL';
SELECT DISTINCT t.i
FROM
(
SELECT a.i
FROM
(
SELECT arrayJoin([1, 2]) AS i
) AS a
UNION
SELECT b.i
FROM
(
SELECT arrayJoin([2, 3]) AS i
) AS b
) AS t
输出:
1
2
3
差集 SQL
SELECT a.i
FROM
(
SELECT arrayJoin([1, 2]) AS i
) AS a
EXCEPT
SELECT b.i
FROM
(
SELECT arrayJoin([2, 3]) AS i
) AS b
输出:1
Ø Tips:ClickHouse 系统内置聚合函数
我们可以使用下面的 SQL 列出 ClickHouse 中聚合函数清单:
SELECT
name,
is_aggregate,
case_insensitive,
alias_to
FROM system.functions
WHERE is_aggregate = 1
输出:
name | is_aggregate | case_insensitive | alias_to |
lagInFrame | 1 | 0 | |
dense_rank | 1 | 1 | |
rank | 1 | 1 | |
exponentialMovingAverage | 1 | 0 | |
sparkbar | 1 | 0 | |
singleValueOrNull | 1 | 0 | |
studentTTest | 1 | 0 | |
rankCorr | 1 | 0 | |
aggThrow | 1 | 0 | |
categoricalInformationValue | 1 | 0 | |
groupArrayMovingAvg | 1 | 0 | |
groupArrayMovingSum | 1 | 0 | |
simpleLinearRegression | 1 | 0 | |
entropy | 1 | 0 | |
quantilesBFloat16 | 1 | 0 | |
maxIntersectionsPosition | 1 | 0 | |
groupBitmapXor | 1 | 0 | |
groupBitmap | 1 | 0 | |
skewPop | 1 | 0 | |
groupBitXor | 1 | 0 | |
groupBitOr | 1 | 0 | |
groupBitmapAnd | 1 | 0 | |
topKWeighted | 1 | 0 | |
stochasticLinearRegression | 1 | 0 | |
corr | 1 | 1 | |
uniqCombined64 | 1 | 0 | |
intervalLengthSum | 1 | 0 | |
uniqCombined | 1 | 0 | |
quantileExactWeighted | 1 | 0 | |
sumMapFilteredWithOverflow | 1 | 0 | |
sumMapFiltered | 1 | 0 | |
minMappedArrays | 1 | 0 | |
sumMappedArrays | 1 | 0 | |
histogram | 1 | 0 | |
quantiles | 1 | 0 | |
sum | 1 | 1 | |
covarPop | 1 | 0 | |
row_number | 1 | 1 | |
kurtPop | 1 | 0 | |
kurtSamp | 1 | 0 | |
skewSamp | 1 | 0 | |
uniqExact | 1 | 0 | |
sumMapWithOverflow | 1 | 0 | |
stddevSamp | 1 | 0 | |
varPop | 1 | 0 | |
corrStable | 1 | 0 | |
quantileTimingWeighted | 1 | 0 | |
covarPopStable | 1 | 0 | |
stddevSampStable | 1 | 0 | |
varSamp | 1 | 0 | |
topK | 1 | 0 | |
last_value | 1 | 1 | |
mannWhitneyUTest | 1 | 0 | |
maxIntersections | 1 | 0 | |
quantilesExact | 1 | 0 | |
uniqHLL12 | 1 | 0 | |
quantileBFloat16 | 1 | 0 | |
uniq | 1 | 0 | |
min | 1 | 1 | |
sequenceNextNode | 1 | 0 | |
quantilesTimingWeighted | 1 | 0 | |
boundingRatio | 1 | 0 | |
any | 1 | 0 | |
anyLast | 1 | 0 | |
deltaSum | 1 | 0 | |
retention | 1 | 0 | |
sequenceMatch | 1 | 0 | |
uniqUpTo | 1 | 0 | |
windowFunnel | 1 | 0 | |
deltaSumTimestamp | 1 | 0 | |
varSampStable | 1 | 0 | |
uniqTheta | 1 | 0 | |
quantilesExactWeighted | 1 | 0 | |
max | 1 | 1 | |
quantilesBFloat16Weighted | 1 | 0 | |
quantileBFloat16Weighted | 1 | 0 | |
sumKahan | 1 | 0 | |
quantilesTDigestWeighted | 1 | 0 | |
groupBitAnd | 1 | 0 | |
quantileTDigest | 1 | 0 | |
quantileTDigestWeighted | 1 | 0 | |
argMax | 1 | 0 | |
quantileDeterministic | 1 | 0 | |
quantilesTDigest | 1 | 0 | |
stochasticLogisticRegression | 1 | 0 | |
argMin | 1 | 0 | |
avg | 1 | 1 | |
covarSampStable | 1 | 0 | |
quantilesTiming | 1 | 0 | |
welchTTest | 1 | 0 | |
covarSamp | 1 | 0 | |
varPopStable | 1 | 0 | |
quantileTiming | 1 | 0 | |
quantileExactInclusive | 1 | 0 | |
quantileExactHigh | 1 | 0 | |
groupArraySample | 1 | 0 | |
quantilesExactLow | 1 | 0 | |
groupBitmapOr | 1 | 0 | |
first_value | 1 | 1 | |
quantileExactExclusive | 1 | 0 | |
quantileExact | 1 | 0 | |
sumCount | 1 | 0 | |
groupArrayInsertAt | 1 | 0 | |
quantilesExactHigh | 1 | 0 | |
sumWithOverflow | 1 | 0 | |
sequenceCount | 1 | 0 | |
quantilesDeterministic | 1 | 0 | |
groupUniqArray | 1 | 0 | |
groupArray | 1 | 0 | |
anyHeavy | 1 | 0 | |
maxMappedArrays | 1 | 0 | |
stddevPop | 1 | 0 | |
quantile | 1 | 0 | |
leadInFrame | 1 | 0 | |
quantilesExactExclusive | 1 | 0 | |
count | 1 | 1 | |
quantilesExactInclusive | 1 | 0 | |
stddevPopStable | 1 | 0 | |
quantileExactLow | 1 | 0 | |
avgWeighted | 1 | 0 | |
BIT_AND | 1 | 1 | groupBitAnd |
VAR_SAMP | 1 | 1 | varSamp |
COVAR_SAMP | 1 | 1 | covarSamp |
VAR_POP | 1 | 1 | varPop |
medianTDigest | 1 | 0 | quantileTDigest |
medianBFloat16 | 1 | 0 | quantileBFloat16 |
medianTimingWeighted | 1 | 0 | quantileTimingWeighted |
medianTiming | 1 | 0 | quantileTiming |
medianExactHigh | 1 | 0 | quantileExactHigh |
BIT_OR | 1 | 1 | groupBitOr |
medianDeterministic | 1 | 0 | quantileDeterministic |
STDDEV_POP | 1 | 1 | stddevPop |
STDDEV_SAMP | 1 | 1 | stddevSamp |
medianExactLow | 1 | 0 | quantileExactLow |
medianTDigestWeighted | 1 | 0 | quantileTDigestWeighted |
medianExact | 1 | 0 | quantileExact |
COVAR_POP | 1 | 1 | covarPop |
medianBFloat16Weighted | 1 | 0 | quantileBFloat16Weighted |
medianExactWeighted | 1 | 0 | quantileExactWeighted |
BIT_XOR | 1 | 1 | groupBitXor |
median | 1 | 0 | quantile |
1.2. Tuple元组类型
在数学中,元组是元素的有限有序列表(序列)。n元组是n 个元素的序列。例如,(4, 2, 8, 5, 7) 表示一个 5 元组。在计算机科学(特别是在程序设计语言和数据库的关系模型),多元组通常被定义为从字段名到特定值的有限函数(值组)。其目的和在数学中一样,就是指出特定的实体。在计算机编程语言类型理论中,元组具有乘积类型,而且是固定的长度,每个元素具备固定的类型。形式化表达就是:
本节主要介绍 ClickHouse 中的元组数据类型。
1.2.1. 元组定义
元组(tuple)其实就是一组数据元素的序列,每个元素都可以有自己独立的类型。
元组是关系数据库中的基本概念:关系是一张表,表中的每行(即数据库中的每条记录)就是一个元组,每列就是一个属性。 在二维表里,元组也称为行。笛卡尔积中每一个元素(d1,d2,…,dn),叫作一个n元组(n-tuple)或简称元组。当关系是一张表,二维表中的行表中的每行(即数据库中的每条记录)就是一个元组,每列就是一个属性。在二维表里,元组也称为记录。
1.2.2. 创建元组
可以使用函数 tuple(T1, T2, ...) 来创建元组。
创建元组的示例:
SELECT tuple(1,'a',NULL) AS x, toTypeName(x) as tp Format Vertical
输出:
SELECT
(1, 'a', NULL) AS x,
toTypeName(x) AS tp
FORMAT Vertical
x: (1,'a',NULL)
tp: Tuple(UInt8, String, Nullable(Nothing))
从上面的输出结果中可以看出,tuple()函数创建与使用圆括号创建元组等价。
实例 SQL:
SELECT
(1, 2, 'a', 0.1, -0.9, NULL) AS x,
toTypeName(x) AS tp
FORMAT Vertical
输出:
x: (1,2,'a',0.1,-0.9,NULL)
tp: Tuple(UInt8, UInt8, String, Float64, Float64, Nullable(Nothing))
在动态创建元组时,ClickHouse会进行类型推断,自动将每个参数的类型赋值为可以存储该参数值的最小类型。如果参数为NULL,那么这个元组元素的类型为Nullable。
元组中的元素可以嵌套元组,例如:
SELECT
(1, 2, tuple(3)) AS x,
toTypeName(x) AS tp
FORMAT Vertical
输出:
x: (1,2,(3))
tp: Tuple(UInt8, UInt8, Tuple(UInt8))
1.2.3. 使用元组
元组可以用在分区键、排序键中。例如:ORDER BY (CounterlD, EventDate) 。元组通常用作IN运算符参数,或创建lambda函数形参列表。
获取元组中的元素
函数:tupleElement(tuple, n)
功能:获取元组中元素的下标为 n的元素。下标从 1 开始。
对应的函数是实例 SQL:
select (1,'a',3,4) as tpl, tupleElement(tpl,2) as t2 Format Vertical
输出:
SELECT
(1, 'a', 3, 4) AS tpl,
tpl.2 AS t2
FORMAT Vertical
tpl: (1,'a',3,4)
t2: a
从上面的输出我们可以看到 tpl.2 这个运算符。tupleElement(x,N) 等价于 x.N,该函数实现了算子 x.N。
还有一个 untuple(tuple) 函数,解开元组中所有元素:
SELECT
(1, 'a', 3, 4) AS tpl,
untuple(tpl)
FORMAT Vertical
输出:
tpl: (1,'a',3,4)
tupleElement((1, 'a', 3, 4), 1): 1
tupleElement((1, 'a', 3, 4), 2): a
tupleElement((1, 'a', 3, 4), 3): 3
tupleElement((1, 'a', 3, 4), 4): 4
元组支持写入表
元组在早期的 ClickHouse版本中,由于复杂数据类型的序列化/反序列化功能未实现,不支持写入到表(内存表除外)中。但是,当前最新版本已经支持了。实例如下。
(1)创建一张简单的表:
CREATE TABLE t1
(
`a` Date,
`b` UInt8,
`c` Tuple(UInt8, String)
)
ENGINE = MergeTree(a, b, 8192)
(2)往表里插入 Tuple 类型的数据:
insert into t1(a,b,c)
values(now(), 1, (1,'a'));
(3)然后,查询表数据:
SELECT
a,
b,
c,
toTypeName(a) AS at,
toTypeName(b) AS bt,
toTypeName(c) AS ct
FROM t1
FORMAT Vertical
输出:
a: 2022-03-04
b: 1
c: (1,'a')
at: Date
bt: UInt8
ct: Tuple(UInt8, String)
1.3. Nested 嵌套数据类型
大部分程序设计语言都提供各种方法,实现基于基础数据类型,构建出复合数据类型。嵌套结构在关系数据库管理系统中并不常见。通常,它只是一张平的表。ClickHouse 提供了一种灵活的数据存储方式。虽然是列式数据库,但它可以实现较底层的结构化,并提供各种函数来提取和聚合数据。ClickHouse支持嵌套数据类型。一张表中可以包含任意多个嵌套数据结构的列,但该嵌套列仅支持一级嵌套。ClickHouse 中的嵌套类型是一个典型的列存多维数组模式(参见第 1 章“1.2.1深度列存储”中关于列存储的数据结构的介绍)。
本节就来介绍 ClickHouse 的嵌套数据类型。
1.3.1. 嵌套类型定义
在ClickHouse中存储嵌套数据,通常有如下用两种方式:
1.存 JSON 格式的String类型(使用JSONExtract(json[, indices_or_keys…], Return_type) 函数操作数据,但是性能可能要差)
2.使用嵌套数据类型(Nested Data Type)。
ClickHouse 嵌套数据类型的关键字是 Nested,只支持一级嵌套。数据结构类似于表格单元格里面嵌套“一张表格”。如下所示:
ID:UInt64 | Name:String | AcademicPerformance: Nested (course:String, score:Float64) | ||||||
1 | 皓轩 |
| ||||||
2 | 语轩 |
|