一、数据分区
数据是以分区目录的形式组织的,每个分区独立分开存储.这种形式,查询数据时,可以有效的跳过无用的数据文件。
1.1 数据分区的规则
分区键的取值,生成分区ID,分区根据ID决定。根据分区键的数据类型不同,分区ID的生成目前有四种规则:
(1)不指定分区键
(2)整形
(3)日期类型(主要根据日期进行分区)
(4)其他类型
数据在写入时,会对照分区ID落入对应的分区
1.2分区目录的生成规则
partitionID_MinBlockNum_MaxBlockNum_Level
BlockNum是一个全局整型,从1开始,每当新创建一个分区目录,此数字就累加1。
MinBlockNum:最小数据块编号。
MaxBlockNum:最大数据块编号。
对于一个新的分区,MinBlockNum和MaxBlockNum的值相同: 2020_03_1_1_0,2020_03_2_2_0
*Level:合并的层级,即某个分区被合并过得次数。不是全局的,而是针对某一个分区。
1.3分区目录的合并过程
MergeTree的分区目录在数据写入过程中被创建。
不同的批次写入数据属于同一分区,也会生成不同的目录,在之后的某个时刻再合并(写入后的10-15分钟),合并后的旧分区目录默认8分钟后删除。
同一个分区的多个目录合并以后的命名规则:
。MinBlockNum: 取同一分区中MinBlockNum值最小的
。MaxBlockNum:取同一分区中MaxBlockNum值最大的
·Level:取同一分区最大的Level值加1
二、索引文件
2.1 稀疏索引
primary.idx文件的一级索引采用稀疏索引。
稠密索引: 每一行索引标记对应一行具体的数据记录。
稀疏索引:每一行索引标记对应一段数据记录(默认索引粒度为8192)。
稀疏索引占用空间小,所以primary.idx内的索引数据常驻内存,取用速度快!
2.2 一级索引
文件:primary.idx
MergeTree的主键使用Primary Key定义,主键定义之后,MergeTree会根据index granularity间隔(默认8192)为数据生成一级索引并保存至primaryidx文件中。这种方式是稀疏索引
**简化形式:通过order by指代主键**
2.3索引生成规则
三、 索引如何执行查询操作
索引的查询过程
索引是如何工作的?对primaryidx文件的查询过程**MarkRange:一小段数据区间**按照index granularity的间隔粒度,将一段完整的数据划分成多个小的数据段,小的数据段就是MarkRangeMarkRange与索引编号对应
案例
共200行数据
indexgranularity大小为5
主键ID为Int,取值从0开始
根据索引生成规则,primary.idx文件内容为:
执行过程
.bin 原始数据 .mark 索引映射
形成一个压缩块
整体数据查询过程
.bin文件形成多个压缩块->.mark文件找到压缩块 ->索引块->解压->再找数据
数据写入过程
查询过程
四、 二进制文件解释
二进制文件格式详解
在介绍了上述目录下的每个文件的功能和作用后,我们一起来看看上面各项文件中,具体存储了什么信息,以及如何去分析这些二进制文件。
在讲解之前,为了更好的看清文件内容,我们一共在users表中插入5条数据:
insert into test.users values ('zhangsan', 'female', 20, '2023-03-07');
insert into test.users values ('lisi', 'female', 22, '2023-03-06');
insert into test.users values ('lilei', 'female', 25, '2023-03-06');
insert into test.users values ('xiaoming', 'female', 27, '2023-03-09');
insert into test.users values ('yaya', 'female', 30, '2023-03-07');SELECT * FROM users ORDER BY age DESC
Query id: ee21ad84-be21-47cf-92bd-55059d59fa6e
┌─name─┬─sex────┬─age─┬───birthday─┐
│ yaya │ female │ 30 │ 2023-03-07 │
└──────┴────────┴─────┴────────────┘
┌─name─────┬─sex────┬─age─┬───birthday─┐
│ xiaoming │ female │ 27 │ 2023-03-09 │
│ lilei │ female │ 25 │ 2023-03-06 │
│ lisi │ female │ 22 │ 2023-03-06 │
│ zhangsan │ female │ 20 │ 2023-03-07 │
└──────────┴────────┴─────┴────────────┘5 rows in set. Elapsed: 0.002 sec.
primary.idx
MergeTree表会根据排序键生成primary.idx表,由users的建表语句可知,我们设置排序的键为age,同时index_granularity = 2。因此对应primary.idx中生成的记录应该为20、25、30三条记录。接下来,我们进入到primary.idx文件中,看下记录的内容是不是我们逻辑上分析的结果:
hexdump -C primary.idx
00000000 14 19 1e 1e |....|
00000004
hexdump可以用来查看二进制文件的十六进制编码。由于定义的age Int8占用1个字节,因此上面的每一个16进制值应该对应于一个Age值。 对上面的十六进制结果做一下转换:
14(十六进制)->20(十进制)
19(十六进制)->25(十进制)
1e(十六进制)->30(十进制)
可以发现,转换成10进制后跟我们一开始的逻辑分析结果一致。证明了我们的猜想,更进一步核实了Clickhouse中primary.idx稀疏索引的原理。
{column}.mrk2
一个{column}.bin文件有1至多个数据压缩块组成,mark2数据标记文件格式比较固定,primary.idx文件中的每个索引在此文件中都有一个对应的Mark,有三列:
Offset in compressed file,8 Bytes,代表该标记指向的压缩数据块在bin文件中的偏移量。
Offset in decompressed block,8 Bytes,代表该标记指向的数据在解压数据块中的偏移量。
Rows count,8 Bytes,行数,通常情况下其等于index_granularity。
因此,每一行mrk2文件共占用24 Bytes。所以通过primary.idx中的索引寻找mrk2文件中对应的Mark非常简单,如果要寻找第n(从0开始)个index,则对应的Mark在mrk2文件中的偏移为n*24,从这个偏移处开始读取24 Bytes即可得到相应的Mark。
age.mrk2
$ hexdump -C age.mrk2
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 02 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 |................|
00000040 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060$ od -An -l age.mrk2
0 0
2 0
2 2
0 4
1 0
5 0
分析下上面的文件内容。由于24 Bytes表示一行数据,因此从上面以每24位做切分,可以得到如下所示的表:
文章来源:https://www.toymoban.com/news/detail-634954.html
由于最后一个mark对应的数据只有一条,所以最后一个行数为1。从表中可以看出,解压文件中的偏移量对应的原表中的age值这与我们在primary.idx中分析出来的3个索引值一一对应。
index_granularity =2,且定义的age Int8占用1个字节,所以每两行对应一个索引,mrk2中也是没两行生成一条对应mark。
由于本次存储的数据 < 默认的压缩大小块64KB,因此所有的数据都在一个压缩块内,压缩文件中的偏移量都是0。
由于最后一个mark对应的数据只有一条,所以最后一个行数为1。文章来源地址https://www.toymoban.com/news/detail-634954.html
到了这里,关于Clickhouse 数据存储的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!