MYSQL中的表空间

MYSQL 的表空间可以理解为其存储在物理磁盘上的 表名.ibd 文件,MYSQL 为了管理方便,增加了很多概念,来一一了解一下。

逻辑概念:Segment

在 B+树的根页面的中,存储了两个 10 字节的字段,PAGE_BTR_SEG_LEAF,
PAGE_BTR_SEG_TOP,这两个字段存储的为 Segment Header 结构,即段头,通过这个字段,可以在表空间中定位到一个 INODE ENTRY 的结构,每个 INODE ENTRY 结构对应一个段。
段是什么呢?段是一个逻辑概念,是 MYSQL 为了优化 磁盘 IO 而提出的,MYSQL 的数据是存储在页里面的,一个页 16KB,同一层的页通过双向链表连接在一起,通过这个双向链表查询数据是随机 IO,因为同一层的页在物理空间上可能不连续,为了优化随机 IO,MYSQL 在页的基础上,提出了区 extent 的概念,一个区由 64 个页组成,也就是 1MB,在段的大小超过 32 个页后,会直接分配若干个区,来存储数据。
这个 INODE ENTRY 结构中即存储了段所对应的一些零散的页面地址以及一些完整的区的地址。

先来看一下向某个段中插入数据的过程:

  • 当段中的数据比较少的 时候,首先会查看表空间中是否有状态为 FREE_FRAG 的区,如果有的话,就直接从里面取出一写零散的页,把数据放进去;否则从表空间申请一个状态为 FREE 的区,把他的状态变为 FREE_FRAG,在从里面申请若干个页,之后不同的段是否零散的页都从这个区里面取,最后区满后,就把其状态变为 FULL_FRAG。 那么如何确定一个区的状态呢? 通过链表的方式:
    1. FREE 链表:状态为 FREE 的区,形成的链表
    2. FREE_FRAG 链表:状态 为 FREE_FRAG 的区,形成的链表
    3. FULL_FRAG 链表:状态为 FULL_FRAG 的区,形成的链表
    这三个链表是属于表空间管理的,因此其存储于表空间的第 0 号页面里面,其页面类型为 FSP_HDR,为了管理每个链表,MYSQL 定义了 LIST BASE NODE,通过这个 NODE,可以快速的得到链表的长度、头节点、尾节点。
  • 当表中的数据占满 32 个页之后,就申请完整的区来插入数据。那么如何确定哪个区属于哪个段呢?还是通过链表的方式来确定的,对于每个段,其会有三个链表
    1. FREE 链表:同一个段中,所有页面都是空闲的区,会被加入到这个链表
    2. NOT_FULL 链表:同一个段中,仍然后空闲的区,会被加入到这个链表
    3. FULL 链表:同一个段中,已经没有空闲的区,会被加入到这个链表

物理概念:区

表空间中的区,对应的就是 64 个连续的页,每个页 16Kb,那就是 1 MB 大小,
区的分类

  1. 空闲的区:现在还没有用到这个区中任何页面
  2. 有剩余空间的碎片区:表示这个碎片区中还有可用的页面,这些页面可能用于某个段,也可能用于 INODE 类型的页面。
  3. 没有剩余空间的碎片区:表示这个碎片区中没有可用的页面
  4. 附属某个段的区:每个索引都有叶子节点段和非叶子节点段,在段中的数据很大时,将使用区作为基本的分配单位

物理改变:组

一个组由 256 个区组成,即 256MB 大小,每个组的第一个页面包含了描述区信息的页面,第二个页面包含了描述 Change Buffer 的信息(不懂,暂时放下)。

不过第一个组略有不同,其第一个页面为 FSP_HDR,除了包含描述区信息外,还包含了描述表空间的信息;第三个页面为 INODE 类型的页面,这个页面里面存储了 INODE ENTRY 结构,来存储关于段的信息。

表空间中的链表

直接用于表空间管理区的有 5 个链表

  1. FREE 链表
  2. FREE_FRAG 链表
  3. FULL_FRAG 链表
    这三个链表连接起来的是 XDES ENTRY 结构,对应的是区的物理结构。
    用于表空间管理段的有 2 个链表
  4. SEG_INODES_FULL 链表:该链表对应的 INODE 类型页面,没有额外空间存储新的 INODE ENTRY 结构
  5. SEG_INODES_FREE 链表: 该链表对应的 INODE 类型页面,有 额外空间存储新的 INODE ENTRY 结构
    这三个链表连接起来的是页的结构,页的类型为 INODE 类型

段用于管理的链表:

  1. FREE 链表:
  2. NOT_FULL 链表:
  3. FULL 链表:
    这三个链表连接起来的是 XDES Entry 结构,对应的是区的物理结构。