Innodb以页为单位存储数据,是操作磁盘的基本单位。一页是16kb大小。有多种类型的页,这里看下存储数据和索引的页,叫做index page。一个index page主要包含以下7部分信息:

【MySQL(十一)】Innodb 页结构_数据

(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)

数据部分都存在user records区。了解各个索引页结构的作用还需要结合innodb的行结构来看。

【MySQL(十一)】Innodb 页结构_数据_02

(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)

一行数据的头信息包括如上信息。delete_mask表明该行记录是否被删除,也就是删除页里一条数据仅仅是标记删除而非物理删除。heap_no代表该记录在页内的偏移量。record_type表明行记录的类型,有四种,0和1分别代表了数据行和索引。2和3是innodb自己加的两条记录,表示最小和最大值,可以理解为正负无穷。next_record是下一条记录的偏移量,所以内页的数据行是靠该字段连接的一条单向链表。如果记录被删除,该记录就会被移出链表。

再回到开始的索引页结构图中,里面的Infimum和Supremum区域分别储存最小和最大记录。Free Space是页内空闲位置的指针。被删除的记录也会形成一个链表,这个空间是可回收的。

另外,在user records区里的数据,是按照索引顺序排序存放的,这个排序是指的链表是有序的,但是实际物理位置可能是无序的。物理位置与插入先后顺序有关。

接着来看下page directory区域。先来想一个问题,根据索引值定位页内的一条记录?我们知道数据是一条有序链表,链表不同于数组,无法直接寻址,所以只能遍历?如果是这样那效率肯定不行。page directory就是用来给页内记录加目录的,可以方便的根据索引值来定位记录。思路大致是将记录按照4-8的数目分组,将每一组索引值最大的记录复制到page directory中,page directory中存放最大值的地方叫做槽。不同的槽也是有序的。行记录的头信息中有一个n_owned的字段就是用来记录如果当前记录是分组的最最大值时,该分组内的记录数目的。这样定位记录时需要先找到对应的槽,然后在对应的分组中遍历即可。

【MySQL(十一)】Innodb 页结构_mysql_03

(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)

接着看下page header部分,这是索引页这种类型的页所特有的结构。里面会包含当前索引页的各种统计信息以及链表头指针等信息。

最后是file header,这是所有类型的页都有的结构。

【MySQL(十一)】Innodb 页结构_数据_04

(本篇图片全部来自掘金小册中《MySQL是怎样运行的》一书)

可以看到,各个数据页也是通过指针连接的,最终形成了一个双向链表。看上去可能长这样:

【MySQL(十一)】Innodb 页结构_mysql_05