MySQL InnoDB数据页结构

本文将介绍 MySQL 中 InnoDB 对数据页的存储方式和存储结构。

一、什么是数据页?

InnoDB 将数据存储至磁盘中,并使用内存作为缓存。为了减少磁盘读写次数,InnoDB 将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位。InnoDB 中页的大小一般为 16KB,InnoDB 会一次最少从磁盘中读取 16KB 的内容至内存中,也会一次最少将内存中 16KB 的内容刷新到磁盘中。

InnoDB 中存在着许多不同类型的页,比如存放表空间头部信息的页、存放 Insert Buffer 信息的页、存放 INODE 信息的页、存放 undo 日志信息的页等等。其中,数据页是其中用于存放记录的页,又名索引页。

二、结构概述

  • 所有的数据页会根据页中记录的主键大小排序组成一个双向链表
  • 数据页中所有记录(包括最大记录和最小记录)会按主键从小到大的顺序串联成一个单向链表
  • 每个数据页会维护一个页目录,用于快速查找记录

一个 InnoDB 数据页的存储空间大致被划分为 7 个部分,其中:

名称 中文名 占用空间大小 简单描述
File Header 文件头部 38 字节 页的一些通用信息
Page Header 页面头部 56 字节 数据页专有的一些信息
Infimum + Supremum 最小记录和最大记录 26 字节 两个虚拟的行记录
User Records 用户记录 不确定 实际存储的行记录内容
Free Space 空闲空间 不确定 页中尚未使用的空间
Page Directory 页面目录 不确定 页中的某些记录的相对位置
File Trailer 文件尾部 8 字节 校验页是否完整

三、File Header - 文件头部

该部分对各种类型的页都通用,描述了页的信息,例如:页的编号、上一页、下一页、页的类型等。

四、Page Header - 页面头部

该部分描述了数据页中记录的状态信息,例如:记录数量、第一条记录地址、槽数、页的校验和等。

五、Infimum + Supremum - 最小记录和最大记录

这是两个虚拟的行记录,它们分别代表最小的记录和最小的记录。

六、User Records - 用户记录 和 Free Space - 空闲空间

记录会按照指定的行格式存储到 Records 之中。

所有记录(包括最大记录和最小记录)会按主键值由小到大的顺序串联成一个单链表

每次插入一条记录,都会从 Free Space 中申请空间划分到 User Records 中,当 Free Space 中的空间全部被用完,就意味着页使用结束,应该申请新的页。

七、Page Directory - 页面目录

1. 什么是页面目录?

为了加快记录的查找,InnoDB 会在页中维护一个 “页面目录”。

所谓 “页面目录”,就是:

  • 将所有记录划分为几个组
  • 设置每个分组的最后一条记录的头信息中的 n_owned 属性,它将表示分组的记录数
  • 记录每个分组最后一条记录的地址偏移量,称为槽,存储于 Page Directory 中

2. 生成步骤

“页面目录” 的生成步骤:

  • 初始时,数据页中只有 “最大记录” 和 “最小记录” 两个 “伪记录”,它们被划分为两个分组
  • 每插入一条记录(所有记录组成的单链表会发生相应的更新),都从 “页面目录” 中找到主键值比本记录大的最小槽,将该槽对应的记录的 n_owned 值递增,表示该分组中新增了一条记录
  • 当某个分组的记录数等于 8 个以后,若再插入记录,会将分组拆分为两个组

3. 页面目录的使用

如果要寻找某条记录,首先使用二分法找到该记录位于的分组的槽,再获取该槽临近的更小槽,从而获取该记录所在分组的最大记录和最小记录,遍历即可获取该记录。

八、File Trailer - 文件尾部

File Trailer 部分用于检测页面的完整性,由两个部分构成:

  • 页的校验和:

    • 和 File Header 中的校验和相对应

    • File Header 中的校验和在内存中计算,会首先被同步到磁盘中;

      File Trailer 中的校验和在完全写入到磁盘后计算

    • File Header 和 File Trailer 中的检验和会会进行比对,如果不相同,则意味着同步中间存在错误

  • 页面被最后修改时对应的日志序列位置:用于校验页面的完整性

参考

  • MySQL 技术内幕
  • MySQL 实战 45 讲
  • MySQL 是怎样运行的:从根儿上理解 MySQL