一、什么是 InnoDB 页?
InnoDB 以 页(Page) 为基本 I/O 单位,默认大小为 16KB (可通过 innodb_page_size 配置为 4KB、8KB、16KB、32KB 或 64KB,但需在初始化时设定)。所有数据(包括表数据、索引、undo 日志等)均以页的形式组织在磁盘与内存中。
注意:页是 逻辑存储单元,不等于操作系统块或磁盘扇区。
二、页的通用结构(Common Page Header)
无论何种类型的页,InnoDB 都为其保留一个 38 字节的通用头部(FIL Header),用于管理页的物理与逻辑属性。主要字段如下:
| 偏移量(字节) | 字段名 | 说明 |
|---|---|---|
| 0 | FIL_PAGE_SPACE_OR_CHKSUM |
空间 ID 或校验和(MySQL 8.0 默认使用 CRC32 校验) |
| 4 | FIL_PAGE_OFFSET |
页在表空间中的偏移(单位:页) |
| 8 | FIL_PAGE_PREV |
前一页的偏移(用于双向链表) |
| 12 | FIL_PAGE_NEXT |
后一页的偏移 |
| 16 | FIL_PAGE_LSN |
最近一次修改的日志序列号(LSN) |
| 24 | FIL_PAGE_TYPE |
页类型 |
| 26 | FIL_PAGE_FILE_FLUSH_LSN |
仅用于系统表空间第一页,记录刷新 LSN |
页尾部(Trailer)包含 8 字节的校验和与 LSN 低 4 字节,用于崩溃检测。
三、主要页类型及其用途
InnoDB 定义了多种页类型,通过 FIL_PAGE_TYPE 字段区分。常见类型如下:
| 页类型(十六进制) | 宏定义(C 源码) | 用途说明 |
|---|---|---|
0x45BF |
FIL_PAGE_INDEX |
B+ 树索引页(含聚簇索引和二级索引) |
0x0000 |
FIL_PAGE_TYPE_ALLOCATED |
新分配但未初始化的页 |
0x0002 |
FIL_PAGE_UNDO_LOG |
Undo 日志页 |
0x0003 |
FIL_PAGE_INODE |
段(Segment)描述信息页 |
0x0004 |
FIL_PAGE_IBUF_FREE_LIST |
插入缓冲空闲列表页 |
0x0005 |
FIL_PAGE_TYPE_SYS |
系统页(如数据字典) |
0x0006 |
FIL_PAGE_TYPE_TRX_SYS |
事务系统页(含回滚段头) |
0x0007 |
FIL_PAGE_TYPE_FSP_HDR |
表空间头页(含 extent 管理信息) |
0x0008 |
FIL_PAGE_TYPE_XDES |
Extent 描述页 |
其中
FIL_PAGE_INDEX是最常接触的类型,承载用户数据与索引。
四、索引页(FIL_PAGE_INDEX)的内部逻辑结构
对于 FIL_PAGE_INDEX 类型的页,其内容分为以下逻辑区域:

- Page Header :包含页级元数据,如记录数(
PAGE_N_RECS)、已用空间、最后插入位置等。 - Infimum/Supremum:虚拟记录,代表页内记录的上下界,用于二分查找。
- User Records:实际存储的行数据或索引条目,按主键顺序组织。
- Page Directory:由"槽(Slot)"组成的稀疏目录,每个槽指向一组记录的开头,加速二分查找(类似跳表思想)。
InnoDB 使用双向链表连接同一级别的页(如叶子页之间),通过 FIL_PAGE_PREV/NEXT 实现范围扫描。此外,空闲页、脏页、LRU 列表等也依赖页头部信息进行管理。
五、如何在实战中应用 InnoDB 页结构知识?
场景 1:分析慢查询是否因页分裂导致
- 现象 :INSERT 延迟突增,
SHOW ENGINE INNODB STATUS显示大量"page splits"。 - 应对 :
- 检查主键是否随机(如 UUID);
- 改用
UUID_TO_BIN(uuid, true)保证时间局部性; - 或切换为自增代理主键。
场景 2:诊断"Buffer Pool 污染"问题
- 现象:大量全表扫描导致热点数据被换出。
- 利用页知识 :
- 通过
INNODB_BUFFER_PAGE查看哪些 SPACE/PAGE 占用最多; - 对大表扫描使用
SQL_NO_CACHE或限制并发; - 考虑拆分 Buffer Pool Instance(
innodb_buffer_pool_instances)隔离影响。
- 通过
场景 3:设计高效二级索引
- 原理:二级索引页只存(索引列 + 主键),回表需再查聚簇索引页。
- 优化 :
- 覆盖索引(Covering Index)避免回表;
- 控制索引列长度(减少单页记录数,提升缓存效率);
- 避免在高基数列上建无选择性的索引(浪费页空间)。
场景 4:崩溃恢复分析
- 若 MySQL 异常重启,可通过页尾部 LSN 与 Redo Log 对比,判断页是否需恢复。
- 工具如
mysqlbinlog --verbose+ibd页解析可辅助定位损坏页。
场景 5:容量规划与成本控制
-
根据页结构估算表大小:text
行数 × (行平均大小 + 页开销) / (页大小 × 填充因子) -
结合压缩特性,预估 SSD 存储成本。
六、常见面试题
-
Q:InnoDB 页默认大小是多少?可以在线修改吗?
A:默认 16KB;不能在线修改,必须在初始化实例时通过
innodb_page_size设置。 -
Q:页头部中的 LSN 有什么作用?
A:用于崩溃恢复时判断页是否需要重做(Redo Log 的 LSN > 页 LSN 则需应用日志)。
-
Q:为什么索引页要有 Infimum 和 Supremum 记录?
A:作为边界哨兵,简化插入和查找逻辑,避免空指针,并支持高效的二分定位。
-
Q:Page Directory 的作用是什么?时间复杂度如何?
A:加速记录查找。先在 Directory 中二分找到 Slot(O(log m)),再线性扫描 Slot 内少量记录(通常 ≤ 8 条),整体接近 O(log n)。
-
Q:如何查看某个页的类型和内容?
A:可使用
mysqlfrm、ibd2sdi(MySQL 8.0+)或第三方工具如innodb_ruby解析.ibd文件。