ClickHouse中的低基数字段优化

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

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

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

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

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

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

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

LowCardinality(String)

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

StringWithDictionary 等同于 LowCardinality(String)

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

SET allow_suspicious_low_cardinality_types = 1

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

CREATE TABLE test2(

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

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

ch7.nauu.com :) desc test2;

写入3亿行测试数据:

INSERT INTO test2 

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

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

SELECT 

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

ch7.nauu.com :) SELECT v1, count() FROM test2 GROUP BY v1 ORDER BY v1;

查询 LowCardinality:

ch7.nauu.com :) SELECT v2, count() FROM test2 GROUP BY v2 ORDER BY v2;

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

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

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

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

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

如果这篇文章对你有帮助,欢迎 订阅、转发、在看 三连击 :)

欢迎大家扫码关注我的 公众号和视频号 :

ClickHouse的秘密基地

nauu的奇思妙想

往期精彩推荐:

1. 从ClickHouse的名字由来讲起

2. 在5000亿数据中大海捞针,需要怎样的硬件做支撑?

3. ClickHouse为何如此之快?

4. 在DB-Engines的排名不高,ClickHouse还值得关注吗?

5. 为什么要写ClickHouse这本书

6.  一分钟视频解读ClickHouse MergeTree

7.  ClickHouse的前世今生-直播回放

  1. ClickHouse各种MergeTree的关系与作用

  2. 如何在ClickHouse中查看SQL执行计划

  3. 使用ClickHouse Playground进行交互式学习

  4. 使用ClickHouse快速实现同比、环比分析

  5. 如何在ClickHouse中实现RANK OVER排序

13.ClickHouse分布式IN & JOIN 查询的避坑指南

本文分享自微信公众号 - ClickHouse的秘密基地(chcave)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )