ClickHouse中的低基数字段优化

Stella981
• 阅读 1096

在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的秘密基地

ClickHouse中的低基数字段优化

nauu的奇思妙想

ClickHouse中的低基数字段优化

往期精彩推荐:

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源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
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
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这