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

皓轩

语文

95.5

数学

97

科学

99

2

语轩

以上是关于ClickHouse 实战:ClickHouse 高级数据类型极简教程的主要内容,如果未能解决你的问题,请参考以下文章

《ClickHouse企业级应用:入门进阶与实战》5 ClickHouse函数

《ClickHouse企业级应用:入门进阶与实战》6 ClickHouse SQL基础

《ClickHouse企业级应用:入门进阶与实战》6 ClickHouse SQL基础

《ClickHouse企业级应用:入门进阶与实战》1 全面了解ClickHouse

极富参考价值!第1章 ClickHouse 简介《ClickHouse 企业级大数据分析引擎实战》...

《ClickHouse企业级应用:入门进阶与实战》8 基于ClickHouse Bitmap实现DMP用户画像标签圈人

(c)2006-2024 SYSTEM All Rights Reserved IT常识