• ClickHouse数据类型


    ClickHouse支持非常丰富的数据类型,如果从数据类型和函数的角度去考虑,甚至可以认为ClickHouse SQL是一门编程语言。ClickHouse中的system.data_type_families表也列出了支持的数据类型。

    1. 整型

    Int8/TINYINT/BOOL/BOOLEAN/INT1 — [-128 : 127]
    Int16/SMALLINT/INT2 — [-32768 : 32767]
    Int32/INT/INT4/INTEGER — [-2147483648 : 2147483647]
    Int64/BIGINT — [-9223372036854775808 : 9223372036854775807]
    Int128 — [-170141183460469231731687303715884105728 : 170141183460469231731687303715884105727]
    Int256 — [-57896044618658097711785492504343953926634992332820282019728792003956564819968 : 57896044618658097711785492504343953926634992332820282019728792003956564819967]
    
    UInt8 — [0 : 255]
    UInt16 — [0 : 65535]
    UInt32 — [0 : 4294967295]
    UInt64 — [0 : 18446744073709551615]
    UInt128 — [0 : 340282366920938463463374607431768211455]
    UInt256 — [0 : 115792089237316195423570985008687907853269984665640564039457584007913129639935]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2. 浮点型

    Float32/FLOAT — float
    Float64/DOUBLE — double
    Inf/-Inf — 无穷大,例如 SELECT 0.5 / 0 的结果为inf 
    NaN — 非数值,例如 SELECT 0 / 0 的结果为NaN
    
    • 1
    • 2
    • 3
    • 4

    浮点型在计算时容易导致精度丢失,所以在表示金额、时间等要求较高的场景尽量使用整型类型。

    3. Decimal

    Decimal(P, S) — P精度,有效范围:[1:76],确定数字可以有多少个十进制位数(包括小数位)。S规模,有效范围:[0:P]。确定数字可以有多少十进制小数位。
    Decimal32(S) — 对应P范围[1 : 9](-1 * 10^(9 - S), 1 * 10^(9 - S))
    Decimal64(S) — 对应P范围[10 : 18](-1 * 10^(18 - S), 1 * 10^(18 - S))
    Decimal128(S) — 对应P范围[19 : 38](-1 * 10^(38 - S), 1 * 10^(38 - S))
    Decimal256(S) — 对应P范围[39 : 76](-1 * 10^(76 - S), 1 * 10^(76 - S))
    
    • 1
    • 2
    • 3
    • 4
    • 5

    例如,Decimal32(4)可以包含-99999.9999到99999.9999之间的数字。由于现代cpu本身不支持128位整数(寄存器限制),因此Decimal128类型是模拟类型,工作速度也明显慢于Decimal32/Decimal64。

    对于加减操作,结果类型S = max(S1, S2)。对于乘法,结果类型S = S1 + S2。对于除法,结果类型S = S1。

    *注意:使用Decimal类型要注意内存溢出问题。

    4. Boolean

    BOOL/BOOLEAN
    
    • 1

    Boolean类型的底层存储类型是UInt8。

    CREATE TABLE test_bool
    (
        `A` Int64,
        `B` Bool
    )
    ENGINE = Memory;
    
    INSERT INTO test_bool VALUES (1, true),(2,0);
    SELECT * FROM test_bool;
    
    ┌─A─┬─B─────┐
    │ 1true  │
    │ 2false │
    └───┴───────┘
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5. String

    String/LONGTEXT/MEDIUMTEXT/TINYTEXT/TEXT/LONGBLOB/MEDIUMBLOB/TINYBLOB/BLOB/VARCHAR/CHAR
    
    • 1

    对于其他关系型数据库中的VARCHAR, BLOB, CLOB等类型,ClickHouse统一定义为String类型。

    6. FixedString

    <column_name> FixedString(N)
    
    • 1

    长度固定的N字节字符串,如长度固定的ID值、MD5值等。如果是UUID值,请使用UUID类型。

    插入数据时,如果字符串包含少于N个字节,则用空字节\0补充字符串,length函数的返回值是常数N。如果字符串包含超过N个字节,则抛出FixedString(N)的过大值异常。在查询数据时,ClickHouse不会删除字符串末尾的空字节。如果使用WHERE子句,应该手动添加空字节来匹配FixedString值。例如定义FixedString(2)类型的字段a,WHERE a = ‘b’ 不会返回任何结果,WHERE a = ‘b\0’ 才会返回为’b’记录。

    7. UUID

    UUID
    
    • 1

    UUID类型的默认值是00000000-0000-0000-0000-000000000000,可以通过generateUUIDv4函数生成UUID。

    CREATE TABLE t_uuid (x UUID, y String) ENGINE=TinyLog;
    INSERT INTO t_uuid SELECT generateUUIDv4(), 'Example 1';
    SELECT * FROM t_uuid;
    
    ┌────────────────────────────────────x─┬─y─────────┐
    │ 417ddc5d-e556-4d27-95dd-a34d84e46a50 │ Example 1 │
    └──────────────────────────────────────┴───────────┘
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    UUID数据类型只支持String数据类型也支持的函数(例如min、max和count),不支持算术运算函数,如abs、sum等。

    8. 日期时间类型

    8.1 Date

    Date类型以两个字节存储,表示自1970-01-01(无符号)以来的天数,支持范围[1970-01-01, 2149-06-06],不包含时区信息。

    CREATE TABLE dt
    (
        `timestamp` Date,
        `event_id` UInt8
    )
    ENGINE = TinyLog;
    
    INSERT INTO dt VALUES (1546300800, 1), ('2019-01-01', 2);
    SELECT * FROM dt;
    
    ┌──timestamp─┬─event_id─┐
    │ 2019-01-011 │
    │ 2019-01-012 │
    └────────────┴──────────┘
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    8.2 Date32

    Date32类型以四个字节存储,表示从1925-01-01开始的天数。允许存储值到2283-11-11。

    CREATE TABLE new
    (
        `timestamp` Date32,
        `event_id` UInt8
    )
    ENGINE = TinyLog;
    
    INSERT INTO new VALUES (4102444800, 1), ('2100-01-01', 2);
    SELECT * FROM new;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    8.3 Datetime

    DateTime([timezone])
    
    • 1

    支持范围:[1970-01-01 00:00:00, 2106-02-07 06:28:15],最小单位是秒。可以通过 SELECT * FROM system.time_zones 查找支持的时区。

    DateTime类型的时区信息不是存储在数据行中,而是存储在列字段的元数据中,在创建表时,可以显式地为DateTime类型的列设置时区。如果没有设置时区,那么ClickHouse将使用ClickHouse服务配置文件中的时区参数值或ClickHouse服务器启动时的操作系统时区。

    DateTime类型的输出格式取决于date_time_output_format 设置,默认是YYYY-MM-DD hh:mm:ss,还可以通过formatDateTime函数格式化输出。在向ClickHouse插入数据时,可以使用不同格式的日期和时间字符串,具体取决于date_time_input_format设置的值,默认是YYYY-MM-DD hh:mm:ss。当插入datetime为整数时,它被视为Unix Timestamp (UTC),然后转为定义的时区值。

    CREATE TABLE dt
    (
        `timestamp` DateTime('Asia/Istanbul'),
        `event_id` UInt8
    )
    ENGINE = TinyLog;
    
    INSERT INTO dt Values (1546300800, 1), ('2019-01-01 00:00:00', 2);
    SELECT * FROM dt WHERE timestamp = toDateTime('2019-01-01 00:00:00', 'Asia/Istanbul');
    SELECT * FROM dt WHERE timestamp = '2019-01-01 00:00:00';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    可以使用字符串值过滤DateTime列值,它将自动转换为DateTime。

    8.4 Datetime64

    DateTime64(precision, [timezone])
    
    • 1

    Datetime64支持纳秒精度,支持范围[1925-01-01 00:00:00, 2283-11-11 23:59:59.99999999]。precision范围[ 0 : 9 ],常用定义:,

    • 3,milliseconds 毫秒
    • 6,microseconds 微秒
    • 9,nanoseconds 纳秒

    在插入数据时,Datetime64同样支持字符串格式写入,但是在where过滤时,和DateTime不同,DateTime64值不会自动从String转换。

    CREATE TABLE dt
    (
        `timestamp` DateTime64(3, 'Asia/Istanbul'),
        `event_id` UInt8
    )
    ENGINE = TinyLog;
    INSERT INTO dt Values (1546300800123, 1), (1546300800.123, 2), ('2019-01-01 00:00:00', 3);
    SELECT * FROM dt;
    
    ┌───────────────timestamp─┬─event_id─┐
    │ 2019-01-01 03:00:00.1231 │
    │ 2019-01-01 03:00:00.1232 │
    │ 2019-01-01 00:00:00.0003 │
    └─────────────────────────┴──────────┘
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    当插入为正数时,后3位表示毫秒精度。当插入为小数时,只有小数位为毫秒精度,需要注意区分。

    9. Enum

    除了上面常见的数据类型,ClickHouse还支持枚举类型,枚举类型值可以通过字符串或者数字指定。ClickHouse底层都是按照数字存储的,但是支持按照名称操作。

    当插入数据时,ClickHouse自动选择8bit和16bit的Enum类型,还可以使用Enum8或Enum16类型来确定存储的大小。8-bit Enum可以包含256个枚举值,范围为[-128, 127],16-bit Enum可以包含65536个枚举值,范围为[-32768, 32767]。

    CREATE TABLE t_enum
    (
        x Enum('hello' = 1, 'world' = 2)
        -- x Enum('hello', 'world')
        -- x Enum('hello' = 1, 'world')
    )
    ENGINE = TinyLog;
    
    SELECT CAST(x, 'Int8') FROM t_enum;
    SELECT toTypeName(CAST('a', 'Enum(\'a\' = 1, \'b\' = 2)')); -- 类型转换
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    定义枚举类型可以省略数字,ClickHouse将自动分配连续的数字,默认从1开始分配号码。也可以指定起始数字。列x只能存储类型定义中列出的值:‘hello’或’world’。如果试图保存任何其他值,ClickHouse将引发异常。这个Enum的8位大小是自动选择的。如果需要查看记录对应的数值,则必须将Enum值转换为整型。

    上述定义的Enum类型不能为空,如果需要保存NULL,则需要定义如下:

    CREATE TABLE t_enum_nullable
    (
        x Nullable( Enum8('hello' = 1, 'world' = 2) )
    )
    ENGINE = TinyLog
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在ORDER BY、GROUP BY、IN、DISTINCT等过程中,enum的行为与相应的数字相同,尤其注意ORDER BY是按照对应数字排序的。Enum值不能与数字进行比较,可以与枚举类型中包含的常量字符串进行比较。如果所比较的字符串不是Enum的有效值,则会抛出异常。支持IN操作符,左边是Enum,右边是一组字符串,字符串是对应Enum的值。可以使用ALTER添加和删除Enum的成员(只有删除的值从未在表中使用时,删除才是安全的)。作为一种保护措施,更改先前定义的Enum成员的数值将引发异常。

    10. LowCardinality

    在常见数据库系统的类型体系中,字符串是最灵活、包容性最强的类型,但是存储成本无疑也最高。为了降低存储成本,提高查询效率,很多DBMS都定义了最大长度的字符串类型,如VARCHAR2(10)等。ClickHouse同样也提供了两种基于String的变种类型优化效率:存储固定长度(按字节数计)字符串的FixedString类型和将字符串转为定长整形枚举值的Enum类型。但是毫无疑问,这两种类型都有局限,尤其是对于大多数长度不固定,且枚举值过多(>100)或者暂时不能穷举全部枚举值的场景。基于此,ClickHouse又提供了一种新的数据类型——LowCardinality。

    LowCardinality是一种改变数据存储方法和数据处理规则的上层修饰类型。ClickHouse将其他数据类型的内部表示形式更改为字典编码,对于许多应用程序,使用字典编码的数据可以显著提高SELECT查询的性能。

    LowCardinality(data_type)
    
    • 1

    其中type表示的原始类型可以是String、FixedString、Date、DateTime,以及除了Decimal之外的所有数值类型。但是,LowCardinality的设计初衷就是为了优化字符串存储,修饰其他类型的效率未必会更高,所以一般多用于data_type为String的场景。在处理字符串时,在字段值不确定的情况下,也建议使用LowCardinality而不是Enum,LowCardinality在使用上提供了更高的灵活性,并且经常显示出相同或更高的效率。

    使用LowCardinality数据类型的效率取决于数据多样性(该字段的count(distinct)值)。如果一个字典包含少于10000个不同的值,那么ClickHouse通常会显示更高的数据读取和存储效率。如果一个字典包含超过100000个不同的值,那么与使用普通数据类型相比,ClickHouse的性能可能更差。

    CREATE TABLE lc_t
    (
        `id` UInt16,
        `strings` LowCardinality(String)
    )
    ENGINE = MergeTree()
    ORDER BY id
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    <未完待续>

  • 相关阅读:
    JS中Class类的静态属性和静态方法
    数据分析学习及实用技巧 —— LF《数据分析集训营》
    主语补足语SC【语法笔记】
    蓝桥杯入门(三)卡片
    KMP算法(多种实现方式)
    Flask-[项目]-搭建短网址系统:flask实现短网址系统,短网址系统,构建短网址系统
    接口自动化测试推荐用什么框架?
    混合IP-SDN网络实现统一智能管理目前需要解决的问题
    qmt量化交易策略小白学习笔记第51期【qmt编程之期货列表--国债期货合约表】
    flutter 常用组件:文本、图片和按钮
  • 原文地址:https://blog.csdn.net/haveanybody/article/details/126085228