页面类型
数据页的类型名其实是:FIL_PAGE_INDEX
类型名称 十六进制 描述
FILPAGE_TYPE_ALLOCATED 0x0000 最新分配,还没使用
FIL_PAGE_UNDO_LOG 0x0002 Undo日志页
FIL_PAGEINODE 0x0003 段信息节点
FILPAGE_IBUF_FREE_LIST 0x0004 Insert Buffer空闲列表
FIL_PAGEIBUF_BITMAP 0x0005 Insert Buffer位图
FILPAGE_TYPE_SYS 0x0006 系统页
FIL_PAGE_TYPE_TRX_SYS 0x0007 事务系统数据
FIL_PAGE_TYPEFSP_HDR 0x0008 表空间头部信息
FILPAGE_TYPEXDES 0x0009 扩展描述页
FILPAGE_TYPE_BLOB 0x000A BLOB页
FIL_PAGEINDEX 0x45BF 索引页,也就是我们所说的数据页
页面通用部分
所有类型的页面都具有的部分:
- File Header: 记录页面的一些通用信息
- File Trailer: 校验页是否完整,保证从内存到磁盘刷新时内容的一致性

File Header 组成
名称 占用空间大小 描述
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_OFFSET
- 2^32 * 16KB = 64TB
- 页号从0开始
FIL_PAGE_PREV 和 FIL_PAGE_NEXT
- 数据页才会使用
FIL_PAGE_TYPE
- 每个页的类型由FIL_PAGE_TYPE表示,比如像数据页的该字段的值就是0x45BF
独立表空间
区 (extent)
- 1个区 = 64个 16KB 页 (1MB)
- 1组 = 256个区

这些组的头几个页面的类型都是类似的:
- FIL_PAGE_TYPE_FSP_HDR 0x0008 表空间头部信息
- FIL_PAGE_IBUF_BITMAP 0x0005 Insert Buffer位图
- FIL_PAGE_INODE 0x0003 段信息节点
- FIL_PAGE_TYPE_XDES 0x0009 扩展描述页

段 (segment)
- 为了使用顺序 I/O, 不以页为单位, 而以区为单位分配空间
- 为了提高扫描效率, 将 B+ 树的叶子节点和内部节点分开, 存储到不同的位置中, 即存储到两个段中, 其中一个段存储叶子节点, 一个段存储内部节点
猜测: B+ 树是有层的概念的, 但是可以看成两种层, 一种是叶子层, 另一种是内部层, 一个区里不要存储两种层, 分开的好处是在一个区中都是同层的节点, 而且节点之间是双向链表, 而且节点之间会挨着, 所以扫描快.
碎片区 (fragment)
在一个碎片区中,并不是所有的页都是为了存储同一个段的数据而存在的,而是碎片区中的页可以用于不同的目的,比如有些页用于段A,有些页用于段B,有些页甚至哪个段都不属于。碎片区直属于表空间,并不属于任何一个段。
- 在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的
- 当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间
段是一些零散的页面以及一些完整的区的集合.
区的分类
状态名 含义
FREE 空闲的区
FREE_FRAG 有剩余空间的碎片区
FULL_FRAG 没有剩余空间的碎片区
FSEG 附属于某个段的区
XDES Entry
为了方便管理这些区,设计InnoDB的大叔设计了一个称为XDES Entry的结构(全称就是Extent Descriptor Entry),每一个区都对应着一个XDES Entry结构,这个结构记录了对应的区的一些属性。我们先看图来对这个结构有个大致的了解:

- Segment ID(8字节)
每一个段都有一个唯一的编号,用ID表示.
- List Node(12字节)
这个部分可以将若干个XDES Entry结构串联成一个链表

- State(4字节)
这个字段表明区的状态。可选的值就是我们前边说过的那4个,分别是:FREE、FREE_FRAG、FULL_FRAG和FSEG
- Page State Bitmap(16字节)
这个部分共占用16个字节,也就是128个比特位。我们说一个区默认有64个页,这128个比特位被划分为64个部分,每个部分2个比特位,对应区中的一个页。第一个位表示对应的页是否是空闲的,第二个比特位还没有用
XDES Entry链表
List Node中的指针,做这么三件事:
- 把状态为FREE的区对应的XDES Entry结构通过List Node来连接成一个链表,这个链表我们就称之为FREE链表。
- 把状态为FREE_FRAG的区对应的XDES Entry结构通过List Node来连接成一个链表,这个链表我们就称之为FREE_FRAG链表。
- 把状态为FULL_FRAG的区对应的XDES Entry结构通过List Node来连接成一个链表,这个链表我们就称之为FULL_FRAG链表。
不同的段也使用 List Node, 不过需要细分:
- FREE链表:同一个段中,所有页面都是空闲的区对应的XDES Entry结构会被加入到这个链表。注意和直属于表空间的FREE链表区别开了,此处的FREE链表是附属于某个段的。
- NOT_FULL链表:同一个段中,仍有空闲空间的区对应的XDES Entry结构会被加入到这个链表。
- FULL链表:同一个段中,已经没有空闲空间的区对应的XDES Entry结构会被加入到这个链表。
每一个索引都对应两个段,每个段都会维护上述的3个链表.
链表基节点
这个结构中包含了链表的头节点和尾节点的指针以及这个链表中包含了多少节点的信息:

一般我们把某个链表对应的List Base Node结构放置在表空间中固定的位置
INODE Entry
记录一下段中的属性.

Segment ID
段的编号
NOT_FULL_N_USED
这个字段指的是在NOT_FULL链表中已经使用了多少个页面。
3个 List Base Node
分别为段的FREE链表、NOT_FULL链表、FULL链表定义了List Base Node
Magic Number
- 这个值是用来标记这个INODE Entry是否已经被初始化了
- 如果这个数字是值的97937874,表明该INODE Entry已经初始化,否则没有被初始化
Fragment Array Entry
我们前边强调过无数次段是一些零散页面和一些完整的区的集合,每个Fragment Array Entry结构都对应着一个零散的页面,这个结构一共4个字节,表示一个零散页面的页号。
各类型页面详细情况
FSP_HDR类型
它存储了表空间的一些整体属性以及第一个组内256个区的对应的XDES Entry结构:

名称 中文名 占用空间大小 简单描述
File Header 文件头部 38字节 页的一些通用信息
File Space Header 表空间头部 112字节 表空间的一些整体属性信息
XDES Entry 区描述信息 10240字节 存储本组256个区对应的属性信息
Empty Space 尚未使用空间 5986字节 用于页结构的填充,没啥实际意义
File Trailer 文件尾部 8字节 校验页是否完整
File Space Header 部分
存储表空间的一些整体属性:

名称 占用空间大小 描述
Space ID 4字节 表空间的ID
Not Used 4字节 这4个字节未被使用,可以忽略
Size 4字节 当前表空间占有的页面数
FREE Limit 4字节 尚未被初始化的最小页号,大于或等于这个页号的区对应的XDES Entry结构都没有被加入FREE链表
Space Flags 4字节 表空间的一些占用存储空间比较小的属性
FRAG_N_USED 4字节 FREE_FRAG链表中已使用的页面数量
List Base Node for FREE List 16字节 FREE链表的基节点
List Base Node for FREE_FRAG List 16字节 FREE_FRAG链表的基节点
List Base Node for FULL_FRAG List 16字节 FULL_FRAG链表的基节点
Next Unused Segment ID 8字节 当前表空间中下一个未使用的 Segment ID
List Base Node for SEG_INODES_FULL List 16字节 SEG_INODES_FULL链表的基节点
List Base Node for SEG_INODES_FREE List 16字节 SEG_INODES_FREE链表的基节点
- List Base Node for FREE List、List Base Node for FREE_FRAG List、List Base Node for FULL_FRAG List
分别是直属于表空间的FREE链表的基节点、FREE_FRAG链表的基节点、FULL_FRAG链表的基节点,这三个链表的基节点在表空间的位置是固定的,就是在表空间的第一个页面(也就是FSP_HDR类型的页面)的File Space Header部分。
- FRAG_N_USED
这个字段表明在FREE_FRAG链表中已经使用的页面数量.
- FREE Limit
在该字段表示的页号之前的区都被初始化了,之后的区尚未被初始化。(全部初始化可能会很慢)
- Next Unused Segment ID
该字段表明当前表空间中最大的段ID的下一个ID,这样在创建新段的时候赋予新段一个唯一的ID值就so easy啦,直接使用这个字段的值就好了。
- Space Flags
表空间对于一些布尔类型的属性,或者只需要寥寥几个比特位搞定的属性都放在了这个Space Flags中存储
标志名称 占用的空间(单位:bit) 描述
POST_ANTELOPE 1 表示文件格式是否大于ANTELOPE
ZIP_SSIZE 4 表示压缩页面的大小
ATOMIC_BLOBS 1 表示是否自动把值非常长的字段放到BLOB页里
PAGE_SSIZE 4 页面大小
DATA_DIR 1 表示表空间是否是从默认的数据目录中获取的
SHARED 1 是否为共享表空间
TEMPORARY 1 是否为临时表空间
ENCRYPTION 1 表空间是否加密
UNUSED 18 没有使用到的比特位
- List Base Node for SEG_INODES_FULL List和List Base Node for SEG_INODES_FREE List
每个段对应的INODE Entry结构会集中存放到一个类型为INODE的页中,如果表空间中的段特别多,则会有多个INODE Entry结构,可能一个页放不下,这些INODE类型的页会组成两种列表:
- SEG_INODES_FULL链表,该链表中的INODE类型的页面都已经被INODE Entry结构填充满了,没空闲空间存放额外的INODE Entry了。
- SEG_INODES_FREE链表,该链表中的INODE类型的页面仍有空闲空间来存放INODE Entry结构。
XDES Entry部分
XDES Entry 0就对应着extent 0,XDES Entry 1就对应着extent 1… 依此类推
XDES类型

IBUF_BITMAP类型
每个分组的第二个页面的类型都是IBUF_BITMAP,这种类型的页里边记录了一些有关Change Buffer的东东
INODE类型
为了存储INODE Entry结构而存在的

名称 中文名 占用空间大小 简单描述
File Header 文件头部 38字节 页的一些通用信息
List Node for INODE Page List 通用链表节点 12字节 存储上一个INODE页面和下一个INODE页面的指针
INODE Entry 段描述信息 16320字节
Empty Space 尚未使用空间 6字节 用于页结构的填充,没啥实际意义
File Trailer 文件尾部 8字节 校验页是否完整
INODE Entry
主要包括对应的段内零散页面的地址以及附属于该段的FREE、NOT_FULL和FULL链表的基节点。每个INODE Entry结构占用192字节,一个页面里可以存储85个这样的结构。
List Node for INODE Page List
一个INODE类型的页面不足以存储所有的段对应的INODE Entry结构,所以就需要额外的INODE类型的页面来存储这些结构。还是为了方便管理这些INODE类型的页面,设计InnoDB的大叔们将这些INODE类型的页面串联成两个不同的链表:
- SEG_INODES_FULL链表:该链表中的INODE类型的页面中已经没有空闲空间来存储额外的INODE Entry结构了。
- SEG_INODES_FREE链表:该链表中的INODE类型的页面中还有空闲空间来存储额外的INODE Entry结构了。
Segment Header 结构的运用
INDEX类型的页有一个Page Header部分:
- 部分字段
名称 占用空间大小 描述
… … …
PAGE_BTR_SEG_LEAF 10字节 B+树叶子段的头部信息,仅在B+树的根页定义
PAGE_BTR_SEG_TOP 10字节 B+树非叶子段的头部信息,仅在B+树的根页定义
其中的PAGE_BTR_SEG_LEAF和PAGE_BTR_SEG_TOP都占用10个字节,它们其实对应一个叫Segment Header的结构,该结构图示如下:

名称 占用字节数 描述
Space ID of the INODE Entry 4 INODE Entry结构所在的表空间ID
Page Number of the INODE Entry 4 INODE Entry结构所在的页面页号
Byte Offset of the INODE Ent 2 INODE Entry结构在该页面中的偏移量
PAGE_BTR_SEG_LEAF记录着叶子节点段对应的INODE Entry结构的地址是哪个表空间的哪个页面的哪个偏移量,PAGE_BTR_SEG_TOP记录着非叶子节点段对应的INODE Entry结构的地址是哪个表空间的哪个页面的哪个偏移量。这样子索引和其对应的段的关系就建立起来了。不过需要注意的一点是,因为一个索引只对应两个段,所以只需要在索引的根页面中记录这两个结构即可。
真实表空间对应的文件大小
随着表中数据的增多,表空间对应的文件也逐渐增大.
