- 一、InnoDB中页的内部结构
- 页结构总览
- 页的详细结构
- 基于页目录的二分查找
- 二、行格式
- 行格式的种类
- Compact行格式
- 记录头信息
- 隐藏列
InnoDB 中页的结构可分为 7 个部分,总大小为16KB(InnoDB 中页的默认大小)。
各个部分的作用如下。
页内部的 7 个结构可分为三部分,即头部、行记录和尾部。
各个结构的详细作用如下表所示。
| 页结构 (共16KB) | 头部 | 文件头(38字节) File Header | 页的通用信息: 页号、前后页的指针、校验和、页面被最后修改时的日志位置等 |
| 页头(56字节) Page Header | 页中记录的状态信息: 当前记录数、页目录的槽数、第一条记录的地址等 | ||
| 行记录 | 最大最小记录(26字节) Infimum + Supremum | 挨着放,头信息中的 heap_no 分别为 0 和 1 ,所以用户记录的 heap_no 是从 2 开始的,记录里只存着这两个单词 | |
| 用户记录(不确定) User Records | 按行格式形成单向链表 | ||
| 空闲空间(不确定) Free Space | 页中未使用的空间 | ||
| 尾部 | 页目录(不确定) Page Directory | 用于在单向链表的行记录中二分查找 | |
| 文件尾(8字节) File Trailer | 校验和、页面被最后修改时的日志位置(首尾呼应,只用于校验页的完整性) |
- 页内的行记录分组,最小记录自己一组,最大记录跟最后一组一起,中间的组每满8个就分裂出新的一组,所以第一组1个、中间组4个、最后一组1 - 8个行记录。
- 每个组的最后一个记录的头信息中存储该组共有几个记录(n_owned 字段)。
- 页目录就是个数组,每个格子称为槽(slot),槽里存储每组最后一个记录的地址偏移量(相当于指针),所以每组的记录数存在最后一个记录中。
| 行格式 | Redundant | Compact | Dynamic | Compressed |
|---|---|---|---|---|
| 版本 | MySQL 5.0前 | MySQL 5.1后 | MySQL 8.0后 | — |
| 主要特点 | 开头存储了记录中所有列的长度,所以冗余 | 针对行溢出,行中存放开头部分的数据 | 针对行溢出,行中只存放溢出页的地址,实际数据在溢出页中 | 针对行溢出,行中只存放溢出页的地址,实际数据在溢出页中 |
compact 行格式中各部分的详细信息如下表所示。
| 记录的额外信息 | 记录的真实数据 | ||||||
| 成分 | 变长字段长度列表 | NULL值列表 | 记录头信息 | 隐藏列 | 真实数据 | ||
| 说明 | 所有变长字段长度的列表(倒序) | 值为null的字段的列表(不包括不可能为null的字段) | 各类头信息 | row_id | transaction_id | roll_pointer | 真正的用户数据的各个字段 |
| 成分 | 预留位 1 和 2 | delete_mask | min_rec_mask | n_owned | heap_no | record_type | Next_record |
|---|---|---|---|---|---|---|---|
| 说明 | — | 该记录是否被删除了(0否,1是),所有被删除的记录连成一个“垃圾链表” | B+树每层非叶节点中的最小记录的该值为1 | 每个组的最后一个记录的该值中存储该组共有几个记录 | 该记录在本页中的位置(从2开始,因为0和1是最大最小记录) | 0- 普通记录 1- B+树非叶节点中的记录 2- 本页最小记录 3- 本页最大记录 | 该记录到下一个记录的地址偏移量(指针) |
| 列名 | 是否必须 | 占用空间 | 描述 |
|---|---|---|---|
| row_id | 否 | 6字节 | 自动生成的主键 |
| transaction_id | 是 | 6字节 | 生成这条记录的事务的id |
| roll_pointer | 是 | 7字节 | 回滚指针,指向上一个版本的该行数据 |
隐藏列的后两列主要用于事务中的回滚操作。



