前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ClickHouse中的低基数字段优化

ClickHouse中的低基数字段优化

作者头像
Nauu
修改2020-05-20 17:06:49
2.7K0
修改2020-05-20 17:06:49
举报

在ClickHouse中,String字符串类型相比其他数据类型而言,一个显著的差异是String类型的大小是不固定的。所以除了常规的列字段压缩手段之外,还延伸出了一些额外的优化思路。

在《ClickHouse原理解析与应用实践》(你没看错,这是最终敲定的书名)这本书的数据定义章节中,曾提过在一些场合可以使用Enum枚举类型代替String字符串,从而将其转换为长度固定、字节更小的数值类型,这样在存储开销、读取效率、分组、排序、去重等操作时都会得到优化。

其实本质上,这就是一种对低基数特征字段的优化思路,只不过枚举类型的使用场景比较苛刻,它要求这些数据预先可知,且能够穷举。那么对于不可预知、无法穷举的数据应该怎么优化呢?

于是,ClickHouse提供了一种修饰数据类型LowCardinality,专门针对低基数特征的字段进行优化。

虽然LowCardinality的初衷是为了优化String,但是一不做二不休,LowCardinality目前还可以支持Int、Date和DateTime类型。

(主要在String场景使用,优化效果更明显)

LowCardinality和Nullable类似,是一种修饰类型,需要和其他数据类型组合使用,例如:

代码语言:sql
复制
LowCardinality(String)
LowCardinality(UInt32)
LowCardinality(Date)

它们也有相应的简写形式,例如:

代码语言:sql
复制
StringWithDictionary 等同于 LowCardinality(String)
UInt32WithDictionary 等同于 LowCardinality(UInt32)
DateWithDictionary 等同于 LowCardinality(Date)

如果需要使用String以外的LowCardinality类型,需要设置

代码语言:javascript
复制
SET allow_suspicious_low_cardinality_types = 1

接下来用一个示例说明,新增一张数据表:

代码语言:sql
复制
CREATE TABLE test2(  
    id UInt32,  
    v1 String,  
    v2 StringWithDictionary
)ENGINE = MergeTree()
ORDER BY id;

其中v1是普通的String类型,v2是经过优化的String类型,之后会用它们来进行比较。

查看表结构,可以看到StringWithDictionary本质是语法糖,最终字段类型还是LowCardinality的形式:

代码语言:sql
复制
ch7.nauu.com :) desc test2;
DESCRIBE TABLE test2
┌─name─┬─type───────────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ id   │ UInt32                 │              │                    │         │                  │                │
│ v1   │ String                 │              │                    │         │                  │                │
│ v2   │ LowCardinality(String) │              │                    │         │                  │                │
└──────┴────────────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘
3 rows in set. Elapsed: 0.007 sec.

写入3亿行测试数据:

代码语言:sql
复制
INSERT INTO test2 WITH
(  
    SELECT ['A','B','C','D']
) AS dict
SELECT number, dict[number%4+1] AS v1, v1 FROM system.numbers LIMIT 300000000

现在我们来分析一下LowCardinality有何其妙之处。

第一个最直观的感受是压缩率更高了,从下面结果可知,在这份数据下v2字段的压缩率提高了一倍:

代码语言:javascript
复制
SELECT     
column,     
any(type) AS type,     
sum(column_data_compressed_bytes) AS compressed,     
sum(column_data_uncompressed_bytes) AS uncompressed,     
sum(rows) AS rowsFROM system.parts_columns
WHERE (table = 'test2') AND (column LIKE 'v%')
GROUP BY columnORDER BY column ASC

┌─column─┬─type───────────────────┬─compressed─┬─uncompressed─┬──────rows─┐
│ v1     │ String                 │    2737458 │    600000000 │ 300000000 │
│ v2     │ LowCardinality(String) │    1433440 │    300593127 │ 300000000 │
└────────┴────────────────────────┴────────────┴──────────────┴───────────┘
2 rows in set. Elapsed: 0.006 sec. 

第二个直观感受是查询变快了,查询普通String:

代码语言:sql
复制
ch7.nauu.com :) SELECT v1, count() FROM test2 GROUP BY v1 ORDER BY v1;
SELECT     
v1,     
count()
FROM test2
GROUP BY v1
ORDER BY v1 ASC

┌─v1─┬──count()─┐
│ A  │ 75000000 │
│ B  │ 75000000 │
│ C  │ 75000000 │
│ D  │ 75000000 │
└────┴──────────┘
4 rows in set. Elapsed: 1.951 sec. Processed 300.00 million rows, 3.00 GB (153.74 million rows/s., 1.54 GB/s.)

查询 LowCardinality:

代码语言:sql
复制
ch7.nauu.com :) SELECT v2, count() FROM test2 GROUP BY v2 ORDER BY v2;
SELECT     
v2,     
count()
FROM test2
GROUP BY v2
ORDER BY v2 ASC

┌─v2─┬──count()─┐
│ A  │ 75000000 │
│ B  │ 75000000 │
│ C  │ 75000000 │
│ D  │ 75000000 │
└────┴──────────┘
4 rows in set. Elapsed: 0.746 sec. Processed 300.00 million rows, 300.22 MB (402.23 million rows/s., 402.53 MB/s.)

查询耗时也缩短了一倍时间。

那么LowCardinality背后的原理是什么呢? 其实从StringWithDictionary的名字已经很明显了,它是通过字典压缩编码进行优化的。

在默认的情况下,声明了LowCardinality的字段会基于数据生成一个全局字典,并利用倒排索引建立Key和位置的对应关系。如果数据的基数大于 8192,也就是说不同的值多于8192个,则会将一个全局字典拆分成多个局部字典(由 low_cardinality_max_dictionary_size 参数控制, 默认8192)。

因为进一步使用了字典压缩,所以查询的IO压力变小了,这是一处优化; 其次在处理数据的某些场合,可以直接使用字典进行操作,不需要将数据全部展开。

由于字典压缩和数据特征息息相关,所以这项特性的最终受益效果,需要在大家各自的环境中进行验证。通常来说,在百万级别基数的数据下,使用LowCardinality的收益效果都是不错的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ClickHouse的秘密基地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档