本文从二进制文件的角度出发,重点介绍ck的MergeTree表引擎下的数据是如何在硬盘上存储的,以便于更好地去理解MergeTree表引擎的原理。
首先创建一个MergeTree的基础表,如下:
注:将索引粒度置为2,并且按行限制索引粒度。
导入一些测试数据,如下:
数据文件在硬盘上的存储如下:
对上述各文件进行分析:
- checksums.txt
校验文件,使用二进制格式存储。它保存了其他各文件的size大小及size的hash值,用于快速校验文件的完整性和真确性。
从中可以看到有各个[column].bin、[coulumn].mrk、minmax_birthday.idx、primary.idx、count.txt、minmax_birthday.idx、partition.dat、skp_idx_age_index.idx等文件的值都会记录在该二进制文件中。
2.columns.txt
表的列信息文件,使用明文格式进行存储。用于保存此数据分区下的列字段信息。
3.count.txt
计数文件,使用明文格式进行存储。用于记录当前数据分区目录下数据的总行数。
4.primary.idx
一级索引(主键索引|稀疏索引)文件,使用二进制格式存储。
MergeTree基于index_granularity=2,每间隔2行数据取主键的值作为稀疏索引。
注:建表没有声明primary key时,主键是以order by为准的,上图的结果是正确的。
5.[column].bin
表的数据文件,使用压缩格式存储,默认为LZ4 压缩格式,用于存储某一列的数据。由于MergeTree采用列式存储,所以每个字段都有其独立的[column].bin文件,并且以字段名来命名,如id.bin等。
clickhouse-compressor --decompress命令可以对数据压缩块进行解压缩。
clickhouse-compressor --stat命令可以查询[column].bin文件中压缩数据的统计信息。
其中第一列表示数据压缩前大小,Int32占4个字节,1-4一共4条数据,一共是16字节,第二列是压缩后的数据大小,因为数据量小,压缩本身还有一些必要的信息要压缩,所以压缩后会比压缩前大。
[column].bin文件第一行16个字节是该文件的checksum值。
第二行第一个字节是0x82,是默认的LZ4算法,第2个到第5个字节是压缩后的数据块的大小,这里是小端模式,这4个字节得倒着看,00 00 00 1b,也就是十进制的27,和clickhouse-compressor --stat里统计的信息一致;第6个到第9个字节是压缩前的数据块的大小,倒着看就是00 00 00 10,也就是十进制的16,和clickhouse-compressor --stat里统计的信息一致。
从第二行第10个字节开始就是LZ4要压缩的内容了。倒着看分别是十进制的1 2 3 4,和插入的数据一致。
6.[coulumn].mrk
表的各列字段标记文件,使用二进制格式进行存储。标记文件中保存了[column].bin文件中数据的偏移量信息。标记文件与稀疏索引文件(primary.idx)对齐,又与[column].bin文件一一对应,所以MergeTree通过标记文件建立了primary.idx稀疏索引与[column].bin数据文件的映射关系。即首先通过稀疏索引文件找到对应数据的偏移量信息,然后基于[coulumn].mrk文件的对应关系,去[column].bin文件中读取相应的数据。
上图为主键索引的标记文件,第一列表示id.bin文件中压缩后数据块的偏移量(字节偏移量),第二列表示id.bin文件解压后数据块的偏移量(字节偏移量)。
注:一个*.bin数据文件是由1至多个数据压缩块组成的,每个压缩块的大小在64KB到1MB之间。
这4条测试数据是在同一个压缩块里的,此压缩块里有2个index_granularity,每个index_granularity有2条记录。因为id是Int32类型的,占4个字节,所以解压后数据块的偏移量是0、8。
三个文件的对应关系如下:
primary.idx | id.mrk | id.bin |
1 | 第0个压缩块,块解压后字节偏移量0,行数:2 | 1 |
2 | ||
3 | 第0个压缩块,块解压后字节偏移量8,行数:2 | 3 |
4 |
7.partition.dat
分区信息文件,用来保存当前分区下分区表达式最终生成的值,使用二进制格式进行存储。
建表时指定是按月分区的,partition by toYYYYMM(birthday),所以partition.dat中为199001。
8.minmax_birthday.idx
用来记录当前分区下分区字段对应原始数据的最小和最大值,使用二进制格式进行存储。
8c和89相差3,与插入数据一致。
9.default_compression_codec.txt
用来记录当前分区下数据压缩方式。
10.skp_idx_age_index.idx与skp_idx_age_index.mrk
分别为二级索引(age)的索引文件和标记文件。