MySQL 8.0Notes

第 13 章:表空间与页面

zjc 于 2026-01-13 发布

这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 InnoDB 以表空间管理文件,以页为基本 IO 单位。理解页面布局是理解 B+Tree、Buffer Pool、redo 和恢复的基础。

13.1 文件类型

文件 职责
system tablespace 数据字典历史结构、undo、双写等,取决于配置
file-per-table .ibd 每表独立表空间
general tablespace 多表共享
temporary tablespace 临时数据
undo tablespace 回滚段
redo log WAL 日志
SHOW VARIABLES LIKE 'innodb_file_per_table';
SELECT SPACE, NAME FROM information_schema.innodb_sys_tablespaces LIMIT 10;

13.2 空间组织

tablespace
  -> segment
     -> extent = 1MB
        -> page = 16KB

默认:

单位 大小
page 16KB
extent 64 pages
segment 若干 extent

页号是表空间内定位页的基本编号。

13.3 页类型

类型 用途
FSP_HDR 文件空间头
IBUF_BITMAP Change Buffer 位图
INODE 段信息
INDEX B+Tree 页
SYSTEM 系统页
TRX_SYS 事务系统
UNDO_LOG Undo 页
BLOB 大字段页

文件头包含页号、表空间 ID、校验和、LSN 等信息。

13.4 INDEX 页布局

fil header
  page header
    infimum + supremum
      user records
        free space
          page directory
            fil trailer

关键区域:

  1. infimum:最小虚拟记录;
  2. supremum:最大虚拟记录;
  3. user records:按主键顺序组织的记录;
  4. page directory:槽,支持二分定位;
  5. trailer:校验和与 LSN。

13.5 行溢出

InnoDB 尽量将行放在 B+Tree 页内。长 VARCHAR、TEXT、BLOB 可能溢出到 BLOB 页。

CREATE TABLE t(
  id BIGINT PRIMARY KEY,
  body TEXT
) ENGINE=InnoDB;

影响:

  1. 聚簇索引页存放前缀;
  2. 剩余数据放溢出页;
  3. 读取大字段增加 IO;
  4. 行格式影响前缀长度;
  5. 大字段会降低缓冲命中率。

查看行格式:

SELECT NAME, ROW_FORMAT
FROM information_schema.innodb_tables
WHERE NAME LIKE 'db/t';

13.6 Doublewrite

脏页
  -> doublewrite file
     -> 数据文件

作用:防止部分页写坏。若数据文件写入中断,可先从 doublewrite 恢复完整页,再应用 redo。

SHOW VARIABLES LIKE 'innodb_doublewrite';

13.7 表空间监控

SELECT file_name, tablespace_name, total_extents, free_extents
FROM information_schema.files;

SHOW GLOBAL STATUS LIKE 'Innodb_data%';

关注:

  1. .ibd 增长;
  2. 碎片;
  3. 临时表空间膨胀;
  4. undo 表空间;
  5. redo 容量;
  6. 可用磁盘水位。

13.8 源码入口

文件 内容
fil0fil.cc 文件和表空间
fut0lst.cc 文件链表
fsp0fsp.cc 文件空间管理
page0page.cc 页面操作
buf0buf.cc 页缓存

调试:

b fil_space_t::io
b buf_page_get_gen

本章小结

表空间由段、区和页组成,INDEX 页是 B+Tree 的物理载体。页头、页目录、记录区和校验信息共同支撑定位与恢复;行溢出和 doublewrite 会直接影响 IO 与可靠性。

思考题

  1. extent 和 page 的关系是什么?
  2. page directory 有什么作用?
  3. 为什么需要 doublewrite?
  4. 长字段为什么会降低缓存效率?
  5. 如何查看表空间和页面相关状态?