背景

说起clickhouse的文件目录结构,由于clickhouse是列式存储,每一列的数据都单独保存到.bin文件中,其实此时我们可以看到每一列的数据除了.bin数据文件之外,还有一个.mrk标记文件存在,熟悉mysql的文件结构的同学肯定很好奇,为什么在mysql中只有索引文件和数据文件存在,索引文件直接指向数据文件的行物理位置即可,为啥clickhouse需要索引文件先执行每一列的.mrk文件,然后再通过.mrk文件才查找到对应的数据位置呢?clickhouse中每一列的.mrk文件的作用究竟何在?

技术追踪

首先我们先看一下mysql的目录组织结构,如下所示,对于innodb引擎,mysql的主键行直接指向数据行的物理位置

clickhouse 索引匹配 clickhouse索引原理_数据库


从mysql的索引结构可以看出,每一条索引记录都有一条执行数据行物理位置的指针,由于mysql是行式存储,通过这个物理位置指针就可以取出完整的一行记录的内容.

看完了mysql的索引结构,我们再来看看clickhouse的索引结构

clickhouse 索引匹配 clickhouse索引原理_mysql_02


对于clickhouse来说,索引的记录并不直接保存执行各个列的物理位置的指针,如上图所示,如果clickhouse的索引记录也是类似mysql那样保存执行各个列的物理位置的指针的话,他需要把每个列的物理位置指针保存到索引中,我们知道clickhouse一般都是宽表结构,一个表中一般包含上百列,如果把每一列的物理位置保存到索引中,那么索引就会变得非常的庞大,几乎没法完全放入到内存中,而且最重要的是比如通过索引查找记录,正常只会取其中的几列数据,所以索引中存储的大量列的指针就显得完全没有必要,所以为了解决上述的问题,clickhouse引入了.mrk标记文件,每一列都有对应的一个.mrk的文件,文件的主要内容是存储每个mark标志(对应8192行记录)对应的bin文件中的物理位置,索引文件中存储的是对应的mark数值,通过mark数值去.mrk文件中查找对应的块(8192行记录)的物理位置,最后通过读取.bin文件获取到8192行列记录。这样整个索引文件存储的仅仅只是mark数值标志,.mrk相当于一个中间的间接文件.这样索引文件就会变得很小。注意这里说的索引不仅仅指主键索引,对于其他跳变索引也是一样的.

此外,获取clickhouse的同一行的多列的数据时,可以使用并行的方式读取不同.bin文件的同一行的记录