第 9 章 存放页面的大池子——InnoDB的表空间

32 阅读10分钟

9.1 回忆一些旧知识

9.1.1 页面类型

类型名称十六进制描述
FIL_PAGE_TYPE_ALLOCATED0x0000最新分配,还没使用
FIL_PAGE_UNDO_LOG0x0002Undo日志页
FIL_PAGE_INODE0x0003段信息节点
FIL_PAGE_IBUF_FREE_LIST0x0004Insert Buffer空闲列表
FIL_PAGE_IBUF_BITMAP0x0005Insert Buffer位图
FIL_PAGE_TYPE_SYS0x0006系统页
FIL_PAGE_TYPE_TRX_SYS0x0007事务系统数据
FIL_PAGE_TYPE_FSP_HDR0x0008表空间头部信息
FIL_PAGE_TYPE_XDES0x0009扩展描述页
FIL_PAGE_TYPE_BLOB0x000ABLOB页
FIL_PAGE_INDEX0x45BF索引页,也就是我们所说的数据页

9.1.2 页面通用部分

在这里插入图片描述

File Header:记录页面的一些通用信息。

名称占用空间描述
FIL_PAGE_SPACE_OR_CHKSUM4 字节页的校验和(checksum值)
FIL_PAGE_OFFSET4 字节页号
FIL_PAGE_PREV4 字节上一个页的页号
FIL_PAGE_NEXT4 字节下一个页的页号
FIL_PAGE_LSN8 字节页面被最后修改时对应的日志序列位置(英文名是:Log SequenceNumber)
FIL_PAGE_TYPE2 字节该页的类型
FIL_PAGE_FILE_FLUSH_LSN8 字节仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的LSN值
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID4 字节页属于哪个表空间

File Trailer:校验页是否完整,保证从内存到磁盘刷新时内容的一致性。

  1. 表空间中每个页都对应着一个页号,也就是FIL_PAGE_OFFSET,它由4字节组成,所以一个表空间最多可以有2^32^个页,按每个页16KB来算,一个表空间最多支持64TB的数据。
  2. 某些类型的页可以组成链表,链表中的页可以不按照物理顺序存储。

9.2 独立表空间结构

9.2.1 区(extent)的概念

连续的64个页就是一个,即一个区占用1MB空间。

每256个区被划分成一

在这里插入图片描述

在这里插入图片描述

从上图可知:

  1. 第一个组最开始的3个页面类型是固定的,分别是:

    • FSP_HDR,登记整个表空间的一些整体属性以及本组所有的区。

    • IBU_BITMAP,存储本组所有页面关于INSERT BUFFER的信息。

    • INODE,存储了许多称为NODE的数据结构。

  2. 其余各组的前两个页面类型是固定的,分别是:

    • XDES类型,extent descriptor,登记本组256个区的属性。
    • IBUF_BITMAP,同上。

9.2.2 段(segment)的概念

为了防止出现相邻的两个区在磁盘相距太远的问题造成大量随机I/O影响性能的问题发生,而引入了的概念。有了以后,为某个索引分配磁盘空间时,就以区为单位,可以消除很多随机I/O。

存放叶子节点的区的集合是一个段;存储非叶子节点的区的集合是另外一个段。也就是说每个索引都会生成两个段,一个叶子节点段,一个非叶子节点段。

碎片(fragment)区:在一个碎片区中,并不是所有的页都为为了存储同一个段的数据而存在的,而是碎片区中的页可以用于不同的段。碎片区直属于表空间,并不属于任何一个段。这时为某个段分配存储空间的策略是:

  1. 在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的。
  2. 当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间。

9.2.3 区的分类

状态名含义说明
FREE空闲的区现在还没有用到这个区中的任何页面
FREE_FRAG有剩余空间的碎片区碎片区中还有可用的页面
FULL_FRAG没有剩余空间的碎片区碎片区中所有页面都被使用,没有空闲页面
FAEG附属于某个段的区除了叶子节点和非叶子节点段,InnoDB还会另外定义一些特殊的段。

处于FREE、FREE_FRAG以及FULL_FRAG三种状态的区直属于表空间;而处理FAEG状态的区是附属于某个段的。

在这里插入图片描述

  • Segment ID(8字节),表示该区所属段的ID。
  • List Node(12字节),将若干个XDES Entry结构串联成一个链表。
  • State(4字节),表明区的状态。
  • Page State Bitmap(16字节),128位,区中每个页2位,第1位表示该页是否空闲,第2位还没有用。

frag:v. (用爆炸装置)蓄意杀伤,n. 碎片弹;手榴弹 fragment:n. 碎片;片段;残存部分,v. (使)破碎,分裂 fragmentation:n. 破碎,分裂;分段储存 内存碎片:memory fragmentation

9.2.3.1 XDES(Extent Descriptor) Entry链表

对于表空间:

  1. 把状态为FREE的区对应的XDES Entry结构连接成一个链表,称为FREE链表
  2. 把状态为FREE_FRAG的区对应的XDES Entry结构连接成一个链表,称为FREE_FRAG链表
  3. 把状态为FULL_FRAG的区对应的XDES Entry结构连接成一个链表,称为FULL_FRAG链表

对于具体的段:

  1. FREE链表:同一个段中,所有页面都是空闲的区对应的XDES Entry结构会被加到这个链表。
  2. NOT_FULL链表:同一个段中,仍有空闲空间的区对应的XDES Entry结构会被加到这个链表。
  3. FULL链表:同一个段中,已经没有空闲空间的区对应的XDES Entry结构会被加到这个链表。

举例:

CREATE TABLE t (
    c1 INT NOT NULL AUTO_INCREMENT,
    c2 VARCHAR(100),
    c3 VARCHAR(100),
    PRIMARY KEY (c1),
    KEY idx_c2 (c2)
)ENGINE=InnoDB;

表t有两个索引,所有共有4个段,每个段维护上述3个链表,总共12个链表。再加上直属表空间的3个链表,整个独立表空间共需要维护15个链表。

9.2.3.2 链表基节点

在这里插入图片描述

  1. List Length,表示该链表一共有多少节点
  2. First Node Page Number 和 First Node Offset,表示该链表的头节点在表空间中的位置
  3. Last Node Page Number 和 Last Node Offset,表示该链表的尾节点在表空间中的位置

我们把某个链表对应的List Base Node结构放在表空间中固定的位置,使用起来就很方便。

9.2.3.3 链表小结
  1. 表空间由若干个区组成
  2. 每个区对应一个 XDES(Extent Descriptor) Entry结构
  3. 直属于表空间的区对应的 XDES Entry 结构可以分为 FREE、FREE_FRAG 和 FULL_FRAG 3个链表
  4. 每个段中的区对应的 XDES Entry 结构可以分为 FREE、NOT_FULL 和 FULL 3个链表
  5. 每个链表对应一个 List Base Node 结构,记录的链表的头、尾、长度等信息,它们被储存在固定位置,便于使用。

9.2.4 段的结构

段是一个逻辑上的概念,由若干个零散的页面以及一些完整的区组成。使用 INODE Entry 来记录段中的属性。

在这里插入图片描述

  1. Segemnt ID,指这个 INODE Entry 结构对应的段的编号(ID)
  2. NOT_FULL_N_USED,指在 NOT_FULL 链表中已经使用了多少个页面。下次从 NOT_FULL 链表分配空闲页面时可以直接根据这个字段的值定位到。
  3. 3个 List Base Node,分别对应段的 FREE、NOT_FULL 和 FULL 三个链表。
  4. Magic Number,标记这个 INODE Entry 是否已经被初始化了。97937874 表明已经初始化。
  5. Fragment Array Entry,每个 Fragment Array Entry 结构对应一个零散的页面。

9.2.5 各类型页面详细情况

9.2.5.1 FSP_HDR 类型

在这里插入图片描述

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

File Space Header部分

在这里插入图片描述

名称大小(字节)描述
Space ID4表空间的 ID
Not Used4未被使用,忽略
Size4当前表空间拥有的页面数
FREE Limit4尚未被初始化的最小页号,大于或等于这个页号的区对应的 XDES Entry 结构都没有被加入 FREE 链表
Space Flags4表空间的一些占用存储空间比较小的属性
FRAG_N_USED4FREE_FRAG 链表中已使用的页面数量
List Base Node for FREE List16FREE 链表的基节点
List Base Node for FREE_FRAG List16FULL_FREG 链表的基节点
List Base Node for FULL_FRAG List16FULL_FREG 链表的基节点
Next Unused Segemnt ID8当前表空间中下一个未使用的 Segemnt ID
List Base Node for SEG_INODES_FULL List16SEG_INODES_FULL 链表的基节点
List Base Node for SEG_INODES_FREE List16SEG_INODES_FREE 链表的基节点
9.2.5.2 XDES 类型

在这里插入图片描述

9.2.5.3 IBUF_BITMAP 类型

Change Buffer

9.2.5.4 INODE 类型

在这里插入图片描述

名称中文名大小(字节)简单描述
File Header文件头部38页的通用信息
List Node for INODE Page List通用链表节点12存储上一个 INODE 页面和下一个 INODE 页面的指针
INODE Entry段描述信息16128
Empty Space尚未使用空间6用于页结构的填充,无实际意义
File Trailer文件尾部8校验页是否完整

9.2.6 Segment Header结构的运用

INDEX 类型页有一个 Page Header 部分,其中

名称占用空间(byte)描述
PAGE_BTR_SEG_LEAF10B+树叶子段的头部信息,仅在B+树的Root页定义
PAGE_BTR_SEG_TOP10B+树非叶子段的头部信息,仅在B+树的Root页定义

这二位都对应了一个叫作 Segemnt Header 的结构:

在这里插入图片描述

PAGE_BTR_SEG_LEAF 记录着叶子节点段对应的 INODE Entry 结构的地址是哪个表空间的哪个页面的哪个偏移量,PAGE_BTR_SEG_TOP 记录着非叶子节点段对应的 INODE Entry 结构的地址是哪个表空间的哪 个页面的哪个偏移量。这样子索引和其对应的段的关系就建立起来了。

9.2.7 真实表空间对应的文件大小

即.idb文件的大小

9.3 系统表空间

9.3.1 系统表空间的整体结构

在这里插入图片描述

9.3.1.1 InnoDB 数据字典

在这里插入图片描述

Data Dictionary Header 页面

在这里插入图片描述

information_schema 系统数据库

USE information_schema;
SHOW TABLES LIKE 'innodb_sys%';

在这里插入图片描述

9.3.2 总结图

在这里插入图片描述

9.4 总结

  1. 不同类型的页面有不同的功能,但都有 File Header 和 File Trailer 的通用结构。
  2. 表空间被划分为许多连续的区,每个区默认64个页,每256个区为一组,每组最开始几个页面的类型是固定的。
  3. 段是一个逻辑上的概念,是某些零散的页面以及一些完整的区的集合。
  4. 每个区对应一个 XDES Entry 结构。
  5. 每个段对应一个 INODE Entry 结构。
  6. 表空间中第一个页面的类型是 FSP_HDR,它存储了表空间的一些整体属性以及第一个组内256个区对应的 XDES Entry 结构。
  7. 除了第一个组以外,其余组的第一个页面的类型为 XDES 。
  8. 每个组的第二个页面的类型为 IBUF_BITMAP。
  9. Segemnt Header 结构占用10字节,为了定位到具体的 INODE Entry 结构。
  10. InnoDB 提供了一系列系统表来描述元数据。