ClickHouse为何如此之快

698 阅读12分钟

开篇上图

答案泽丽移速快啊。

泽丽 技能连招: 开大 QQQQE开滑、远离鸽子今年掘金练度上个Level 3, 废话不多说,上链接。 1642737364_9.jpg

进入正题

一 、ClickHouse简介

列式 数据库管理系统,查询速度快, 支持SQL 够简洁了吧。

摘抄官方文档部分

行式存储

RowWatchIDJavaEnableTitleGoodEventEventTime
#0893543506621Investor Relations12016-05-18 05:19:20
#1903295099580Contact us12016-05-18 08:10:20
#2899537060541Mission12016-05-18 07:38:00
#N

行式读取

row-oriented.gif

列式存储

Row:#0#1#2#N
WatchID:893543506629032950995889953706054
JavaEnable:101
Title:Investor RelationsContact usMission
GoodEvent:111
EventTime:2016-05-18 05:19:202016-05-18 08:10:202016-05-18 07:38:00

列式读取

column-oriented.gif

结论:

  1. 针对分析类查询,通常只需要读取表的一小部分列。在列式数据库中你可以只读取你需要的数据。例如,如果只需要读取100列中的5列,这将帮助你最少减少20倍的I/O消耗。
  2. 由于数据总是打包成批量读取的,所以压缩是非常容易的。同时数据按列分别存储这也更容易压缩。这进一步降低了I/O的体积。
  3. 由于I/O的降低,这将帮助更多的数据被系统缓存 列式数据库更适合于OLAP(联机分析处理)场景(对于大多数查询而言,处理速度至少提高了100倍)

性能对比 image.png

二、clickhouse速度快的特性

列式存储优势

查询变快最简单有效的途径,减少数据扫描范围和数据传输大小

  1. 对比于行式存储减少扫描范围: 行式存储会逐行扫描, 并筛选我们选择的字段进行输出,会产生冗余的扫描工作。而列式存储就不会出现这样的问题。

  2. 列式存储同列具有相同的类型和实现语义,重复项的可能性高,易于压缩。clickhouse默认压缩算法LZ4.

着眼硬件,向量化引擎

image.png

  • 传统的数据库查询执行都是采用一次一tuple的pipleline执行模式。这样CPU的大部分处理时不是用来真正的处理数据,而是在遍历查询操作树,这样CPU的有效利用率不高。同时这也会导致低指令缓存性能和频繁跳转。更加糟糕的是,这种方式的执行,不能够利用到现在新硬件的新的能力来加速查询的执行。在执行引擎中,另外一个解决方案就是改变一次一tuple 为一次一列的模式。这也是我们向量化执行引擎的一个基础。

  • 向量化引擎是跟列存储技术绑定的,因为列存每列的数据存储在一起,可以认为这些数据是以数组的方式存储的。基于这样的特征,当该列数据需要进行某一同样操作,可以通过一个循环来高效完成对这个数据块各个值的计算。

  • ClickHouse实现了向量执行引擎(Vectorized execution engine),对内存中的列式数据,一个batch调用一次SIMD指令(而非每一行调用一次),不仅减少了函数调用次数、降低了cache miss,而且可以充分发挥SIMD指令的并行能力,大幅缩短了计算耗时。向量执行引擎,通常能够带来数倍的性能提升。

向量化执行引擎的优势在于:

  • 可以减少节点间的调度,提高CPU的利用率。
  • 因为相同类型的一类数据放在一起,可以更容易的利用硬件与编译的新优化特征。

补充:

  • Apache Doris 第一个生产版本也采用向量化引擎 mp.weixin.qq.com/s/Ju3K67jOr…
  • Hbase没找到相关资料支持向量化引擎执行
  • 向量化引擎可以利用SIMD(Single Instruction Multiple Data)指令实现单条指令操作多条数据, 在CPU寄存器层面实现数据的并行操作,就很nb,很快。

算法在前,抽象在后

  • 以字符串为例, 有一本专门讲解字符串搜索的书,名为 《Handbook of Exact String Matching Algorithms》 列举了常见的字符串搜索算法,Click一种方法都没有用,因为性能不够快。在字符串搜索方面针对不同场景,ClickHouse最终选择了这些算法: 对于常量,使用Volnisky算法,对于非常量,使用CPU的向量化执行SIMD,暴力优化;正则匹配使用re2和hyperscan算法。性能是算法选择的首要考量指标。

  • 特定场景,特殊优化: 针对同一个场景的不同状况,选择使用不同的实现方式,尽可能将性能最大化。关于这一点,其实在前面介绍字符串查询时,针对不同场景选择不同算法的思路就有体现了。类似的例子还有很多,例如去重计数uniqCombined函数,会根据数据量的不同选择不同的算法:当数据量较小的时候,会选择Array保存;当数据量中等的时候,会选择HashSet;而当数据量很大的时候,则使用HyperLogLog算法。对于数据结构比较清晰的场景,会通过代码生成技术实现循环展开,以减少循环次数。接着就是大家熟知的大杀器——向量化执行了。SIMD被广泛地应用于文本转换、数据过滤、数据解压和JSON转换等场景。相较于单纯地使用CPU,利用寄存器暴力优化也算是一种降维打击了。

不太明显的优点:多线程与分布式

多线程与分布式这个大多竞品都有,有手就行。

分区

支持分区,设置分区键,可按照分区键过滤掉无用数据。下面MergeTree有说明。

多主架构

集群中的每个节点角色对等,客户端访问任意一个节点都能得到相同的效果。不用再区分多主控节点、数据节点和计算节点,集群中的所有功能节点都相同。

三、被人广泛接受的其他特性(除了速度快)

完备的DBMS

  • DDL 可以动态地创建、修改或删除数据库、表和视图
  • DML:可以动态查询、插入、修改或删除数据
  • 权限控制:可以按照用户粒度设置数据库或者表的操作权限,保障数据安全
  • 数据备份与恢复:提供了数据的导出与导入恢复机制
  • 分布式管理:提供集群模式,能够自动管理多个数据库节点

关系模型与SQL查询

相比HBase和Redis这类NoSQL数据库,ClickHouse使用关系模型 描述数据并提供了传统数据库的概念(数据库、表、视图和函数 等)。与此同时,ClickHouse完全使用SQL作为查询语言(支持 GROUP BY、ORDER BY、JOIN、IN等大部分标准SQL),这使得它 平易近人,容易理解和学习。因为关系型数据库和SQL语言,可以说 是软件领域发展至今应用最为广泛的技术之一,拥有极高的“群众基 础”。也正因为ClickHouse提供了标准协议的SQL查询接口,使得现有 的第三方分析可视化系统可以轻松与它集成对接。在SQL解析方面, ClickHouse是大小写敏感的,这意味着SELECT a和SELECT A所代表的 语义是不同的。

关系模型相比文档和键值对等其他模型,拥有更好的描述能力, 也能够更加清晰地表述实体间的关系。更重要的是,在OLAP领域,已 有的大量数据建模工作都是基于关系模型展开的(星型模型、雪花模 型乃至宽表模型)。ClickHouse使用了关系模型,所以将构建在传统 关系型数据库或数据仓库之上的系统迁移到ClickHouse的成本会变得 更低,可以直接沿用之前的经验成果

数据分片与分布式查询

数据分片是将数据进行横向切分,这是一种在面对海量数据的场 景下,解决存储和查询瓶颈的有效手段,是一种分治思想的体现。 ClickHouse支持分片,而分片则依赖集群。每个集群由1到多个分片组 成,而每个分片则对应了ClickHouse的1个服务节点。分片的数量上限 取决于节点数量(1个分片只能对应1个服务节点)。 ClickHouse并不像其他分布式系统那样,拥有高度自动化的分片 功能。

ClickHouse提供了本地表(Local Table)与分布式表 (Distributed Table)的概念。一张本地表等同于一份数据的分片。而 分布式表本身不存储任何数据,它是本地表的访问代理,其作用类似 分库中间件。借助分布式表,能够代理访问多个数据分片,从而实现 分布式查询。

这种设计类似数据库的分库和分表,十分灵活。例如在业务系统 上线的初期,数据体量并不高,此时数据表并不需要多个分片。所以 使用单个节点的本地表(单个数据分片)即可满足业务需求,待到业 务增长、数据量增大的时候,再通过新增数据分片的方式分流数据, 并通过分布式表实现分布式查询。这就好比一辆手动挡赛车,它将所 有的选择权都交到了使用者的手中

四、ClickHouse核心表引擎 MergeTree

建表

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
    name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
    ...
    INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
    INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]

建表SQL与插入数据

CREATE TABLE pd_location
(
    `id` UInt64,
    `country_code` String,
    `location_code` String,
    `location_name` String,
    `create_time` DateTime
)
ENGINE = MergeTree()
PARTITION BY toYYYYMMDD(create_time)
ORDER BY (id, location_code)
primary key id


insert into pd_location values
('1','PN','PN0001','pandanode1','2022-04-20 00:00:00'),
('1','PN','PN0002','pandanode2','2022-04-20 00:00:00'),
('2','PN','PN0001','pandanode1','2022-04-22 00:00:00'),
('3','PN','PN0001','pandanode1','2022-04-23 00:00:00')
  • ORDER BY — 排序键。

    可以是一组列的元组或任意的表达式。 例如: ORDER BY (CounterID, EventDate) 。

    如果没有使用 PRIMARY KEY 显式指定的主键,ClickHouse 会使用排序键作为主键。

    如果不需要排序,可以使用 ORDER BY tuple(). 参考 选择主键

  • PARTITION BY — 分区键 ,可选项。

    要按月分区,可以使用表达式 toYYYYMM(date_column) ,这里的 date_column 是一个 Date 类型的列。分区名的格式会是 "YYYYMM" 。

  • PRIMARY KEY - 如果要 选择与排序键不同的主键,在这里指定,可选项。

    默认情况下主键跟排序键(由 ORDER BY 子句指定)相同。
    因此,大部分情况下不需要再专门指定一个 PRIMARY KEY 子句。

  • 分区键作用

    • 降低数据扫描范围,优化查询速度。例如插入数据的示例。按天进行分区,按日期查询,只扫描这个区块的数据,而不用全表扫描。涉及分区后,涉及到跨分区的操作,clickhouse会以区为单位多线程并行处理。通过分区表目录,可以看出每个分区独立存储在一个文件目录下。

分区表的目录

image.png

1.png

统一分区两个Block合并过程 2.png 合并原理:LSM树(Log Structured Merge Tree,结构化合并树)

clickhouse目录结构

image.png

  • columns.txt 列信息文件,使用文本文件存储, 用于保存分区下的列字段信息

  • primary.idx 索引文件,用于存放稀疏索引,目的能够快速定位到data.bin中数据的位置。

  • data.bin: 数据文件,使用压缩格式存储, 默认使用LZ4压缩格式,用于存储某一列的数据

  • data.mrk3 列字段标记,保存了bin文件中数据的偏移量信息,MergeTree通过标记文件建立了primary.idx稀疏索引与bin数据文件的映射关系。

  • partition.dat 用于保存当前分区表达式最终生成值

  • mixmax_create_time.idx 用于记录当前分区字段对应原始数据的最小值和最大值。

MergeTree 一级索引

  • 稀疏索引占用的索引存储空间比较小,数据量大场景,可以利用primary.idx内的索引数据常驻内存,加快查询速度。

  • 默认索引粒度大小为8192

  • 每隔一个索引粒度会取该粒度范围内的第一个主键值作为索引保存到primary.idx文件中

image.png

二级索引(跳数索引)

like查询分词做的

image.png

MergeTree 读取过程

image.png

参考:《Clickhouse原理解析与实践》

走进云溪 数据库之 ClickHouse原理解析-李盟

这可能是B站讲得最好的ClickHouse教程完整版全集

ClickHouse架构及应用