ClickHouse 数据类型

4,424 阅读3分钟

数据类型

ClickHouse 的数据类型大致划分为:基本数据类型,复合数据类型,特殊类型。

和普遍使用的 Mysql 进行比较。

基本类型

只有数值,字符串,时间。没有 Boolean ,但可以通过 0/1 来替代。

基本类型 对应 Mysql
Int8 Tinyint
Int16 Smallint
Int32 Int
Int64 Bigint
Float32 Float
Float64 Double
String Varchar Text Blob
FixedString(N) Char
UUID [8-4-4-4-12]
DateTime [到秒]
DateTime64 [到亚秒]
Date [到天]

复合类型

提供了数组,元组,枚举,嵌套四种复合类型。

Array

select [1,2,Null] as a, toTypeName(a);

┌─a──────────┬─toTypeName([1, 2, NULL])─┐
│ [1,2,NULL]         │ Array(Nullable(UInt8))   │
└────────────┴────────────────┘

一个数组里面时可以包含多个数据类型,但是多个数据类型必须兼容,[1, 'click'] 这种的就会报错。所以在建表建议标明字段类型【也建议在建表的时候将所以的字段名类型和注释都标注清楚】:

create table test (
  c1 Array(String)
) engine = TinyLog;

Tuple

SELECT
    (1, 'click', now()) AS a,
    toTypeName(a)

┌─a───────────────────┬─toTypeName(tuple(1, 'click', now()))─┐
│ (1,'click','2020-06-06 05:59:57') │ Tuple(UInt8, String, DateTime)       │
└───────────────────────────────────┴─────────┘

从这里可以看出,元组是支持不同的数据类型,彼此之间不需要兼容。所以在建表的时候也建议指定字段类型。

Enum

定义常量时会经常使用该类型,分 Enum8/Enum16Enum 固定使用 Enum(String=Int) 的键值对格式。

CREATE TABLE test (
    `c1` Enum('click' = 1, 'house' = 2, 'java' = 3)
) ENGINE = TinyLog
insert into test values ('click');
insert into test values ('house');

建表的时候 Key/Value 是不允许重复的。其次,Key/Value 不能同时为 Null ,但是Key允许空字符串。

Nested

CREATE TABLE test_nest (
    `name` String,
    `age` Int8,
    `dept` Nested(
    		id UInt8,
    		name String
    )
)
ENGINE = TinyLog

但是实际上 Nested 会传统的嵌套类型不一样,不能理解为 test_nestdept 不是一对一的结构:

insert into test_nest values ('nest', 18, 1000, '大数据组')

Exception on client:
Code: 53. DB::Exception: Type mismatch in IN or VALUES section. Expected: Array(UInt8). Got: UInt64

异常显示需要 Array,而不是单纯的 Int。所以这里也就明白:嵌套类型本质是一个多维数组的结构。

嵌套类型的一个字段对应一个数组。字段对应的数组内的数量没有限制,但是字段之间需要数组内的数量对齐。

SELECT
    name,
    dept.id,
    dept.name
FROM test_nest

┌─name─┬─dept.id───────┬─dept.name───────────────┐
│ nest  │ [232,233,235]      │ ['clickhouse','kafka','debezium'] │
│ tube  │ [7,9,10]           │ ['flink','spark','kudu']          │
└────┴─────────────┴─────────────────────┘

访问的时候和 struct 的访问方式一致。

特殊类型

Nullable

Nullable 类似 java 的 Optional,表示某个基本类型可以为 Null

从上面的介绍:

  1. Nullable 只能和基本类型搭配使用;

  2. 不能使用在 Array/Tuple 这种复合类型上;

  3. 不能作为索引字段【Order by()】;

  4. 慎用 Nullable ,写入写出性能不好。因为它会生成单独的文件。

    【这个和 Mysql 的设计类似,Null 也需要额外的空间存储,只是mysql是存储在每一个记录的头中。】

Domain

分为 IPv4 IPv6。其实本质都是对整型,字符串进行的封装。

  • IPv4 使用 UInt32 存储。
  • IPv6 使用 FixedString(16) 存储。

可能会问,为什么不就直接使用整型和String存储呢?

  1. Domain 类型支持格式检查,错误的IP数据是不被允许写入到数据库中;
  2. IPv4 不使用String存储,使用空间更小,查询性能更快。

虽然本质是使用String存储,但是类型上是不属于 String ,所以不支持隐形的类型转换。如果你需要输出IP字符串形式,需要 IPv4NumToString() 进行显示转换。