ClickHouse为什么那么快

为啥他能这么快呢?设计如此=-=

概述

ClickHouse设计的初衷是to filter and aggregate data as fast as possible

再优秀的系统的设计也只能对各个指标进行取舍,无法兼得,而ClickHouse的最重要的指标和任务就是做好这样的一件事:尽可能快的过滤和聚合数据。实际上,这也是传统的OLAP系统所追求的指标。体现到语义上,就是实现GROUP BY查询的实现。

为了实现这一目的,ClickHouse在上层设计上做出了如下的优化:

  • Column-oriented storage
  • Indexes
  • Block
  • Pre-sort
  • Data compression
  • Vectorized query execution
  • Scalability

然而许多其他的数据库使用的相似的优化策略,为什么ClickHouse能够脱颖而出呢?另一个值得关注的点是其底层实现细节。一个观点是:ClickHouse并没有太多的新的方法或者理论,而是将前人的研究成果应用到了OLAP这个领域。因此可以说,ClickHouse是一个非常优秀及经典的工程化项目,是人类计算机工程的结晶。

Column-oriented storage

列式存储能够显著的降低磁盘IO。对于OLAP场景中,每次只关心一个大宽表中的某几列的场景,相比于行式存储,列式存储仅需获取需要的数据,磁盘的IO理论上能够降低为所关心的列与所有列之比。因此,越是宽的表,行式存储的优势越明显。

同样,使用ClickHouse时,也一定要使用列式存储数据库的方式来查询数据,查询时指定具体的列,否则性能提升会不明显。

Block

ClickHouse使用Block实现批处理。Block 是ClickHouse中的数据最小处理单元,表示内存中表的子集(chunk)的容器,是由三元组: (IColumn, IDataType, 列名) 构成的集合。在查询执行期间,数据是按 Block 进行处理的。如果我们有一个 Block ,那么就有了数据(在 IColumn 对象中),有了数据的类型信息告诉我们如何处理该列,同时也有了列名(来自表的原始列名,或人为指定的用于临时计算结果的名字)。
当我们遍历一个块中的列进行某些函数计算时,会把结果列加入到块中,但不会更改函数参数中的列,因为操作是不可变的。之后,不需要的列可以从块中删除,但不是修改。这对于消除公共子表达式非常方便。

Pre-sort

ClickHouse会对插入的数据进行预排序(基于LSM算法)。这里设计的原因是针对大数据量场景,为了处理上百亿条记录的数据,一般的查询返回的数据量都非常大,如果数据是无序的,对于按字段聚合或者范围查询的场景,会大大增加磁盘IO次的次数。

to be discussed
这里预排序是对每个字段都预排序吗?如果按照字段A进行范围筛选,获取相应的字段B进行计算,按照ClickHouse的列式存储和预排序,这里的流程是如何实现的?ClickHouse是如何根据排序后的A,找到对应行的B的呢?

Data compression

数据压缩是提升ClickHouse性能的一个关键。我们发现,前面介绍的列存、分块和预排序,实际上都对压缩有着一定的好处,

  • 列式的存储使得数据更有规律,可以更好地进行数据压缩(相同类型的数据放在一起,对压缩更加友好);同时,能够最小化数据扫描的范围。
  • 排序后的数据可以使用更有效的压缩方式来进行处理。
  • 按照block作为最小处理单元的原因是,虽然数据被压缩后能够有效减少数据大小,降低存储空间并加速数据传输效率,但数据的压缩和解压动作,其本身也会带来额外的性能损耗。所以需要控制被压缩数据的大小,以求在性能损耗和压缩率之间寻求一种平衡。在具体读取某一列数据时(.bin文件),首先需要将压缩数据加载到内存并解压,这样才能进行后续的数据处理。通过压缩数据块,可以在不读取整个.bin文件的情况下将读取粒度降低到压缩数据块级别,从而进一步缩小数据读取的范围。

Indexes

由于ClickHouse实现了在插入时进行了预排序,因此其索引做的非常简单,无需像MySQL需要设置单独的索引文件索引数据的位置,因为其数据本身就是有序的。

ClickHouse的索引包括一级索引标记二级索引一级索引记录每一个block第一个值。例如一组一亿行的数据,主键范围从1~100,000,000。存储到ClickHouse后按照8192行为一个block,那么一共有12208个block。索引为1,8193,16635……在查询时只需要就可以根据值确定到需要读取哪几个block了。但是仅仅靠定位到具体哪个block还是不够,因为我们仍不清楚这个block在文件的哪个位置,因此就有了标记来记录block在文件中的偏移量。由于一级索引非常小,1亿条数据只需要1万多行的索引,因此一级索引可以常驻内存,加速查找。

Vectorized query execution

ClickHouse使用C++进行开发,通过向量化的实现进行数据的高效查询。主要包括提升CPU 缓存利用率,以及使用 SIMD CPU 指令。
Clickhouse在所有能够提高CPU计算效率的地方,都大量的使用了SIMD,频繁调用的基础函数,大量的进行可并行计算,将工程上的优化做到了极致。

以下的代码是一个例子,对于一个简单的额大小写转换的方法,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值