基于 Mysql5.7
一、回顾 InnoDB 逻辑结构图
二、页结构
”页“ 是InnoDB 管理存储空间的基本单位,一个”页“默认 16 KB。
在 InnoDB 中存在不同种类型的”页“,根据不同功能进行划分。
如:
- 存放表空间头部信息的页
- 存放 Insert Buffer 信息的页
- 存放 INODE 信息的页
-
2.1、InnoDB 存储引擎”页“结构

如上图,InnoDB 存储引擎”页“结构由七部分组成 File Header(文件头)
- Page Header(页头)
- Infimun + Supremum Records
- User Records(用户记录,即行记录)
- Free Space(空闲空间)
- Page Directory(页目录)
- File Tailer(文件结尾信息)
File Header(文件头)
File Header 用来记录页的一些头信息,如:页的编号,上一页,下一页等。由八部分组成,共占用 38 字节
| 名称 | 占用空间的大小 | 描述 |
|---|---|---|
| FIL_PAGE_SPACE_OR_CHKSUM | 4字节 | 页的校验和(checksum值) |
| FIL_PAGE_OFFSET | 4字节 | 页号 |
| FIL_PAGE_PREV | 4字节 | 上一个页的页号 |
| FIL_PAGE_NEXT | 4字节 | 下一个页的页号 |
| FIL_PAGE_LSN | 8字节 | 页面被最后修改时对应的日志序列位置(Log Sequence Number) |
| FIL_PAGE_TYPE | 2字节 | 该页的类型 |
| FIL_PAGE_FILE_FLUSH_LSN | 8 字节 | 仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的 LSN值 |
| FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID | 4字节 | 页属于哪个表空间 |
FIL_PAGE_SPACE_OR_CHKSUM
当前页面的校验和(checksum)。 通过算法把一个很长的字符串变成一个较短的唯一串,较短的唯一串叫做校验和。 比较两个很长的字符串直接对比校验和能够节省时间的损耗。
FIL_PAGE_OFFSET
每一个也都有一个单独的页号。InnoDB 通过页号唯一确定一个页,并定位。
FIL_PAGE_TYPE | 类型名称 | 十六进制 | 描述 | | —- | —- | —- | | FIL_PAGE_TYPE_ALLOCATED | 0x0000 | 最新分配,还没使用 | | FIL_PAGE_UNDO_LOG | 0x0002 | Undo日志页 | | FIL_PAGE_INODE | 0x003 | 段信息节点 | | FIL_PAGE_IBUF_FREE_LIST | 0x004 | Insert Buffer 空闲列表 | | FIL_PAGE_IBUF_BITMAP | 0x005 | Insert Buffer 位图 | | FIL_PAGE_TYPE_SYS | 0x0006 | 系统页 | | FIL_PAGE_TYPE_TRX_SYS | 0x007 | 事务系统数据 | | FIL_PAGE_TYPE_FSP_HDR | 0x008 | 表空间头部信息 | | FIL_PAGE_TYPE_XDES | 0x009 | 扩展描述页 | | FIL_PAGE_TYPE_BLOB | 0x00A | BLOB页 | | FIL_PAGE_INDEX | 0x45BF | 索引页,也就是我们所说的数据页 |
FIL_PAGE_PREV和FIL_PAGE_NEXT
InnoDB 以页单位存放数据,但是存放的数据可能占用较大的空间,InnoDB可能不可以一次性为这么多数据分配一个非常大存储空间, 于是需要把数据分散到多个不连续的页中存储,这时候就需要把这些页关联起来,通过 FIL_PAGE_PREV和FIL_PAGE_NEXT,分别指向上一页和下一页想成双向链表,把数据串起来,如下图:
![[MySQL]-[InnoDB]-逻辑结构-页结构 - 图3](/uploads/projects/it-learn@mysql/80e5b23514a68b002c7cf0539a6a874e.png)
Page Header(页头)
Page Header 记录了数据页的状态信息,如:本页存储了多少条记录,第一条记录地址,页目录中存储了多少槽等。由14部分组成,共占 56 字节。
| 名称 | 占用空间大小 | 描述 |
|---|---|---|
| PAGE_N_DIR_SLOTS | 2 字节 | Page Directory(页目录)中的 Slot(槽)数。 |
| PAGE_HEAP_TOP | 2字节 | 还未使用的空间最小地址,也就是说从该地址之后就是 Free Space |
| PAGE_N_HEAP | 2 字节 | 本页中的记录的数量(包括最大和最小记录以及标记为删除的记录) |
| PAGE_FREE | 2字节 | 第一个已经标记为删除的记录地址(各个已删除的记录通过 next_record也会组成一个单链表,这个单链表中的记录可以被重新利用) |
| PAGE_GARBAGE | 2字节 | 已删除记录占用的字节数 |
| PAGE_LAST_INSERT | 2字节 | 最后插入记录的位置 |
| PAGE_DIRECTION | 2字节 | 记录插入的方向 |
| PAGE_N_DIRECTION | 2字节 | 一个方向连续插入的记录数量 |
| PAGE_N_RECS | 2字节 | 该页中记录的数量(不包括最小和最大记录以及被标记为删除的记录) |
| PAGE_MAX_TRX_ID | 8字节 | 修改当前页的最大事务 ID,该值仅在二级索引中定义 |
| PAGE_LEVEL | 2字节 | 当前页在 B+树中所在的层级 |
| PAGE_INDEX_ID | 8 字节 | 索引 ID,表示当前页属于哪个索引 |
| PAGE_BTR_SEG_LEAF | 10字节 | B+树叶子段的头部信息,仅在 B+ 树的 Root页定义 |
| PAGE_BTR_SEG_TOP | 10字节 | B+树非叶子段的头部信息,仅在 B+树的 Root页定义 |
Infimum + Supremum
在 InnoDB 存储引擎中,每个数据页中都有两条虚拟的记录,用来限定记录的边界。
Infimum:该页中的最小记录,该页中主键最小。
Supremum:该页中的最大记录,该页中主键最大。
这两个值在页创建的时候创建,并且不会被删除。
在 Compact行格式和 Redundant 行格式下,两者占用的字节数不相同。
两条记录与数据记录的位置关系
User Records 和 FreeSpace
User Records :实际存储记录的内容,这些记录根据主键进行排序。
FreeSpace:空闲空间,链表数据结构。当一条记录被删除,该空间会被加入空闲链表中。
Page Directory(页目录)
MySQL 中页使用B+树进行存储,通过B+树搜索也只能搜索到页。
对于记录的查询仍然需要到页中查找。
页中存储了多条记录,直接通过遍历的方式效率低,索引如引入了 Page Directory 概念。
Page Directory 由一个个 slot(槽)组成,slot(槽)存储了真实记录的指针。
InnoDB 的 slot(槽)是一个稀疏目录(sparse directory),一个 slot(槽)可能属于多个记录,最少属于4条,最多属于8条。
每一个 slot(槽)按照顺序排列,而 slot(槽)对应的记录也是按照顺序排列。
通过 slot(槽)查找数据,就是二分法的查找方式。
首先通过二分确定了 slot(槽)的位置,然后遍历 slot(槽)的数据,最多遍历 8次,O(1)的复杂度。
而 Page(页)是在内存中的数据,整个操作是在内存中完成的,且查询数据都是排列整齐的数据,所以查询速度可以忽略不计。
File Trailer
InnoDB 存储引擎会把磁盘的数据以页(16KB)为单位加载到内存中,针对数据的修改直接在内存中完成。
然后在某个时间点将内存的数据写入到磁盘中。
而内存在写数据到磁盘的过程中可能出现断电等导致写操作中断。这时候页的数据就是不完整的。
File Trailer 就是为了检验页的完整性。
File Trailer 只有一个FIL_PAGE_END_LSN 部分,占用 8 字节。
- 前四个字节:代表该页的 checksum值
- 后四个字节:和 File Header 中的 FIL_PAGE_LSN 相同。
File Trailer 和 File Header 中的 FIL_PAGE_SPACE_OR_CHKSUM 和 FIL_PAGE_LSN 进行比较,以此来保证页的完整性。
三、知识点
1、页的类型
2、槽(二分法)
InnoDB会为把页中的记录划分为若⼲个组,每个组的最后⼀个记录的地址偏移量作为⼀个槽,存放在Page Directory中,所以在⼀个页中根据主键查找记录是⾮常快的,分为两步:

