这篇文章是自己学习mysql随手写的杂记,编辑混乱且不够严谨,请勿参考,谢谢!

表空间分为系统表空间和独立表空间,一般情况下一张表会对应一个独立表空间。为了管理表空间,设计了各种类型的页和链表,表空间的管理是非常复杂的。那么表空间存的是什么东西呢?记录是怎么存在于表空间中的呢?为了管理表空间又引入了哪些概念呢?

表空间可以看成是由数据页组成的集合,存储记录时,从表空间中取一个页来存记录,但是我们考虑以下情况:

在进行索引的范围查询时,叶子节点是以双链表的形式互连的,在确定了扫描的最小值和最大值之后,紧接着就是扫描这些值介于最大值和最小值中间的记录,如果存储这些记录的时候按页申请存储空间,那么这些页之间很可能不是物理上连续的,这就造成了范围扫描时的随机IO。而随机IO是很损耗性能的。因此我们在存储记录时,是不是可以申请连续的页来存储记录,这样范围扫描的时候就避免了随机IO,答案是可以的。但是注意到这里我们一直扫描的是叶子节点,如果我们把叶子节点和非叶子节点放在一起看待就浪费了,因此对于一个索引,mysql innodb会创建两个段(段是区的集合,准确的说是由一些零散的页和区组成),一个是叶子节点段,一个是非叶子节点段。至此引入了区的概念:连续64个页构成一个区,一个页大小为16KB,那么一个区大小为1M,又规定256个区为一个组,表空间第一个组的前几个页类型是固定的,后面组的前几个页类型也是固定的。现在以区为单位申请存储空间,最小则为1M,如果只是存储少量的数据,1M的空间就浪费了,为了节省存储空间,把表空间中的区分为几个类型:

  • 没有使用的区(FREE)
  • 有剩余空间的区(FREE_FRAG)
  • 没有剩余空间的区(FULL_FRAG)
  • 直属于某个段的区(FSEG)

当向表中插入数据时,也就是向段中插入数据。

  • 段先从表空间直属的FREE_FRAG中取出页存记录,如果没有FREE_FRAG类型的区,则取一个FREE的区将其变为FREE_FRAG,然后取页存记录。如果FREE_FRAG已经满,则将其变为FULL_FRAG状态,表明区中没有剩余的空间了。
  • 如果段中的记录页超过32个,则申请存储空间时以区为单位进行申请。

在上面存储中,我们如何得知哪些区是空闲的,哪些是已经用完的,这个时候可以用链表把不同状态的区连起来,这样在查找时就能够很快速的定位。还有一点就是段中的区,如何得知哪些区是属于哪个段,mysql为段中的区创建了3个链表,分别对应没有使用的区,有剩余空间的区,没有剩余空间的区。mysql还定义了基节点存放上述链表的头部和尾部,这些基节点存放于表空间的固定位置。区有一个XDES entry结构与之对应,段有一个INODE entry与之对应,有多个段通过链表连接。从上我们可以知道一个索引有2个段,一个段有3个链表,再加上直属于表空间的3个链表就是9个链表。

表空间第0页是一个比较特别的页,它存的是表空间的一些整体属性已经本组256个区的信息。

完。