clickhouse查询表现的更多秘密

在这里插入图片描述
哈喽,小伙伴们,承诺大家的clickhouse专栏系列开始了!博主也是一名入门者,践行者&布道者。希望一方面记录所思所为,另一方面把工作中实践的一些东西拿来分享给广大朋友,以飨读者!才疏学浅,难免有误!还望大家多多指正。最后希望这个专栏的文章能对大家有帮助。
在这里我对clickhouse不做过多的介绍。你们关注他,一定也了解他。目前国内头部大厂纷纷落地,仅字节跳动集群规模已达千台。我一直在想这第一篇到底要先写什么,最后我决定,作为一款OLAP产品,查询性能一定是用户最关注的。所以这第一篇我们来聊聊查询。

加速查询

获得好的查询加速,我们可以从以下方面入手:

  • 加速查询通过增加线程数;
  • 加速查询通过减少读取;
  • 查询的效率趋于I/O的扩展
  • 使用prewhere语句来帮助过滤非索引字段数据

另外,我们还有一些要注意的地方:

  • 确保最优的分区数。不是分区数越多越好!分区数过多,不仅在clickhouse启动服务时增加load data parts的时间,同时对于replicatedMergeTree(复制)表也会导致Zookeeper上Znode的数量增多。so,保持每张表分区数在百级别,不要到千级别及以上。
  • 在压缩前使用不同的编码方式来减小数据大小。clickhouse提供了多种编码方式,见下文。通过编码方式,结合压缩算法,提升数据压缩率,能有效减少压缩后的数据量,从而减少I/O,提升性能。感兴趣的朋友可以了解一下这篇文章:压缩算法对比测试
  • 优化主键索引以及减少数据大小和索引选择。clickhouse内部以主键排序存储。选择不同的主键,对于查询性能影响很大。这个需要结合业务方常用查询SQL来确定。
  • 原表之外通过物化视图来传输数据。我们可以事先进行一些聚合操作,然后将其构建到clickhouse提供的物化视图上。这样也可以进一步提升性能。

目前索引类型

索引类型名最佳使用方式
minmax数据最大最小范围; 适用于像时间戳这样的强局部性的数字类型
set唯一值
ngrambf_v1Presence of character ngrams, works with =, LIKE, search predicates; 适用于长字符串
tokenbf_v1类似于ngram,但用于空格间隔的字符串;适用于标签查询
bloomfilter列中的值

编码方式提升压缩效率

这里给大家隆重推荐LowCardinality(String)。该特性用字典编码的值,即将string映射到字典索引(字符串被编码为 Position-可以理解为索引,并通过 position-to-string 的映射引用字典。使用该特性后,可以极大地减少数据存储大小。后边我会再写博文给大家展示使用这个特性后的性能测试对比。
另外,CODEC(DoubleDelta),可用于任何等宽的数据类型。尤其是时间戳类型。

CREATE TABLE codec_example_table
(
    EventTime DateTime CODEC(DoubleDelta),
    price Float32 CODEC(Gorilla)
)
ENGINE = MergeTree()

这里查询效率提升是因为更少的I/O,好的编码方式可以有效减少I/O处理的数据大小。

编码方式总览

编码方式最适用于
LowCardinality不多于1万个值的字符串(低基数的),且字符串长度越长,效果提升越好
Delta时间序列
DoubleDelta增长的计数
GorillaGauge data (bounces around mean)
T64除去随机哈希的整型

注:可以使用ZSTD或者LZ4等来压缩
工作中,我们可以使用system.columns查看数据大小,如下:

SELECT table,
formatReadableSize(sum(data_compressed_bytes)) tc,
formatReadableSize(sum(data_uncompressed_bytes)) tu,
sum(data_compressed_bytes) / sum(data_uncompressed_bytes) as ratio
FROM system.columns
WHERE database = currentDatabase()
GROUP BY table ORDER BY table

更多的一些参考资料

Amplifying ClickHouse Capacity with Multi-Volume Storage
ClickHouse Materialized Views: The Magic Continues
Strength in Numbers: Introduction to ClickHouse Cluster Performance
Performance Analysis of ClickHouse Queries

附录:编码方式

【博主偷个懒,直接上英文】

  • Delta. Delta encoding stores the difference between consecutive values. The difference typically has smaller byte-size and cardinality, especially for sequences. It can be efficiently compressed later with LZ4 or ZSTD.
  • DoubleDelta. With this encoding ClickHouse stores difference between consecutive deltas. It gives even better results for slowly changing sequences. To use an analogy from physics, Delta encodes speed, and DoubleDelta encodes acceleration.
  • Gorilla. This one is inspired by a Facebook article some time ago [http://www.vldb.org/pvldb/vol8/p1816-teller.pdf], and nobody remembers the academic name of the algorithm anymore. Gorilla encoding is very efficient for values that does not change often. It is applicable both to float and integer data types.
  • T64. This encoding is unique to ClickHouse. It calculates max and min values for the encoded range, and then strips the higher bits by transposing a 64-bit matrix (which is where the T64 name comes from). At the end we have a more compact bit representation of the same data. The encoding is universal for integer data types, and does not require any special properties from the data other than locality of values.

文末小彩蛋

在实际工作中,我们遇到了用户使用了大量聚合查询且以某个分区作为过滤条件的场景(后边也会整理这方面的文章)。在4千万记录级别上,未优化前查询性能始终在1秒以上。后边我们采用了下面的小技巧(假设用户使用ID字段聚合):

1.在分布式(DistributedMergeTree)表中用ID做分片键;
2.在分片表(也叫本地表)中用ID做order by
3.然后设置参数distributed_group_by_no_merge = 1
这个参数(默认为0)含义就是本地表做完聚合后,不再在分布式表中聚合所有数据。因此需要确保相同的ID值出现在同一个分片上(步骤1确保了这一点)。这样在每个分片上做group by之后,在分布式表做数据汇总即可。从而提升了查询性能。

使用了这个技巧后,查询耗时不到1秒,大概在700毫秒左右。


更多好文,敬请期待…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值