本章将向读者残缺地介绍 clickhouse 存储引擎的存储模型及工作机制
文件组织
在大部分的 DBMS 中,数据库实质上就是一个由各种子目录和文件组成的文件目录,clickhouse 当然也不例外。clickhouse 默认数据目录在 /var/lib/clickhouse/data 目录中。所有的数据库都会在该目录中创立一个子文件夹。下图展现了 clickhouse 对数据文件的组织。
每一个数据库都会在 clickhouse 的 data 目录中创立一个子目录,clickhouse 默认携带 default 和 system 两个数据库。default 顾名思义就是默认数据库,system 是存储 clickhouse 服务器相干信息的数据库,例如连接数、资源占用等。
上图展现了 clickhouse 通过官网提供的入门教程操作后,导入的数据库的文件模式。能够看到,在 tutorial 文件夹中,建设了两个子目录,每个子目录为即为一张数据表。进入 hits_v1 目录后又能看到两个子目录和一个文本文件。
分区目录
分区目录下的子目录和文件的含意如下:
目录名 | 类型 | 阐明 |
---|---|---|
201403_1_10_2 | 目录 | 分区目录一个或多个,因为分区 +LSM 生成的 |
detached | 目录 | 通过 DETACH 语句卸载后的表分区寄存地位 |
format_version.txt | 文本文件 | 纯文本,记录存储的格局 |
分区目录形成
分区目录的形成,依照 分区 ID_最小数据块编号_最大数据块编号_层级形成。在本例中,分区 ID 是 201403, 最小数据块编号是 1,最大数据库编号是 10,层级是 2。数据块编号从 1 开始自增,新创建的数据库最大和最小编号雷同,当产生合并时会将其批改为合并的数据块编号。同时每次合并都会将层级减少 1。对于合并的详情能够查看本系列的番外篇——LSM。
分区 ID 由用户在创立表时制订,容许用户创立多个分区键,每个分区键之间用‘-’相连。在本例中只应用了一个分区键,即工夫字段,依照年月分区。分区的益处在于进步并发度和减速局部查问。
数据目录
进入分区目录后,就能看到数据实在存储的数据目录的构造了。
columns.txt
该文件是一个文本文件,存储了表构造信息,能够用文本编辑关上。
count.txt
该文件也是一个文本文件,存储了该分区下的行数。能够用文本文件关上。在用户执行 select count() from xxx 时实质上就是间接返回了该文件的内容,而不须要遍历数据。因而 clickhouse 的 count()的速度十分快。
同时,这边也比照一下 MySQL 和 PostgreSQL 的实现,在上述两个关系型数据库中,其罕用的存储引擎,都没有应用 clickhouse 的这种计划。读者们是否答复出为了 MySQL 或 pg 要舍弃简略的计划而应用遍历么?
这个问题的答案是因为事务的可见性,MySQL 和 pg 都是用 MVCC 机制的事务控制技术,这意味着对于不同事务中执行 select count(*)的后果是不同的,对于 A 事务中执行的 insert 或 delete,对于本事务中是可见的,也就是说在本事务中执行的 count 是计算了 insert 和 delete 影响的。而对于 B 事务,在 A 事务提交前,是不能看到 A 事务中对数据的操作的。因而 AB 两个事务中执行的 count 后的后果可能是不同的。如果应用 clickhouse 的计划,就无奈实现上述需要。而 clickhouse 则不须要反对事务,因而应用了绝对简略的计划。
primary.idx
主键索引,详情请参考本系列第四章。
checksums.txt
二进制文件,校验和。用于疾速校验数据是否被篡改。、
default_compression_codec.txt
新版本减少的一个文件,在旧版本时无。该文件是一个文本文件,存储了数据文件中应用的压缩编码器。clickhouse 提供了多种压缩算法供用户抉择,默认应用 LZ4。
[column].mrk3
列的标记文件,详情请参考本系列第四章。
[column].bin
真正存储数据的数据文件。下一节将对其对深入分析。每一列都会生成一个独自的 bin 文件。
skp_idx_[column].idx
跳数索引,在应用了二级索引时会生成。否则这不生成
skp_idx_[column].mrk
跳数索引标记文件,在应用了二级索引时会生成。否则这不生成
本节具体介绍 clickhouse 中存储引擎的文件组织。将一张表拆解到具体的目录和文件中,读者应该能对 clickhouse 的存储系统有了初步理解。下一节将向读者展现如何读懂数据文件。
数据组织
本节将向读者展现如何读取 bin 文件。因为 bin 文件是二进制文件,在读取时须要借助工具,无奈应用文本文件进行读取。在 windows 操作系统下倡议应用 winhex,mac 零碎举荐 hex friend。
数据文件构造
上图展现了一个 bin 文件的构造。bin 文件应用小端字节序存储。bin 文件中按 block 为单位排列数据,每个 block 文件有 16 字节校验和,1 字节压缩形式,4 字节压缩后大小和 4 字节的压缩前大小组成。每个 block 起始地址由如下公式确定:
- offset(n)=offset(n-1)+25+ 压缩后大小(n>=2)
- offset(1)=0
校验和
前 16 为测验和区域用于疾速验证数据是否残缺。
压缩形式
默认为 0x82。clickhouse 共反对 4 种压缩形式,别离为 LZ4(0x82)、ZSTD(0x90)、Multiple(0x91)、Delta(0x92)。
压缩后大小
存储在 data 区域的数据的大小。须要根据此大小计算下一个 BLOCK 的偏移量。
压缩前大小
data 区域存储的数据在压缩前的大小。能够根据此计算压缩比。
data 区
data 区存储数据,大小为头信息第 18~21 字节示意的大小。拿到 data 区数据后,因为是压缩后的,因而无奈间接辨认,须要依照压缩形式进行解压缩后,能力辨认。
example
下图是通过 clickhouse 通过官网提供的入门教程指引操作后,应用二进制阅读器关上 hits_v1 表的 UserAgent.bin 文件的截图,曾经对头信息进行了色彩标记。
通过读取头信息,咱们晓得该数据库是应用 LZ4 算法压缩,压缩后大小为 0x000049AC 即 18860 字节。压缩前大小为 0x00010000 即 65536 字节,压缩比约为 1:3.4≈29%。图中显示的是 AC490000,因为 clickhouse 应用小端字节序,因而理论为 0x000049AC。
接着,咱们从 data 区起始地址开始复制 18860 字节的压缩后数据,将其通过 LZ4 算法解压,能够失去原始数据,如下图所示。解压缩程序的源码曾经上传到 github, 读者能够拜访该仓库,自行下载试验。github 地址:cfcz48/lz4compress (github.com)
接下来,咱们通过查问 columns.txt,能够看出 UserAgent 列是 UInt8 的数据类型,也就是说每个数据时无符号的 8 位整数。因而联合上一步失去的原始数据,每 8 位即为一行数据。例如 0x04 示意十进制的 4。即上图中的原始数据为 4。下图展现了前 20 位原始数据解码后的后果:
咱们在用 SQL 查问前 20 位数据,看看是否统一:
总结
本章对 clickhouse 的存储引擎的文件组织进行了具体地阐明,并给出了一个例子,不便读者了解。下一章将为读者具体介绍数据插入的过程。