MySql的表空间
本文最后更新于:2023年12月4日 晚上
独立表空间结构
区(extent)
空间中的页实在是太多了,为了更好的管理这些页面,设计InnoDB的提出了区(英文名:extent)的概念。对于16KB的页来说,连续的64个页就是一个区,也就是说一个区默认占用1MB空间大小。不论是系统表空间还是独立表空间,都可以看成是由若干个区组成的,每256个区被划分成一组。
第一个组最开始的3个页面的类型是固定的,也就是说extent 0这个区最开始的3个页面的类型是固定的,分别是:
FSP_HDR类型:这个类型的页面是用来登记整个表空间的一些整体属性以及本组所有的区,也就是extent 0 ~ extent 255这256个区的属性。需要注意的一点是,整个表空间只有一个FSP_HDR类型的页面。
IBUF_BITMAP类型:这个类型的页面是存储本组所有的区的所有页面关于INSERT BUFFER的信息。
INODE类型:这个类型的页面存储了许多称为INODE的数据结构。
其余各组最开始的2个页面的类型是固定的,也就是说extent 256、extent 512这些区最开始的2个页面的类型是固定的,分别是:
XDES类型:全称是extent descriptor,用来登记本组256个区的属性,也就是说对于在extent 256区中的该类型页面存储的就是extent 256 ~ extent 511这些区的属性,对于在extent 512区中的该类型页面存储的就是extent 512 ~ extent 767这些区的属性。上边介绍的FSP_HDR类型的页面其实和XDES类型的页面的作用类似,只不过FSP_HDR类型的页面还会额外存储一些表空间的属性。
IBUF_BITMAP类型:上边介绍过了。
为什么要提出区
我们每向表中插入一条记录时,也就是想索引添加记录,B+树的每一层中的页都会形成一个双向链表,如果是以页为单位来分配存储空间的话,双向链表相邻的两个页之间的物理位置可能离得非常远。我们介绍B+树索引的适用场景的时候特别提到范围查询只需要定位到最左边的记录和最右边的记录,然后沿着双向链表一直扫描就可以了,而如果链表中相邻的两个页物理位置离得非常远,就是所谓的随机I/O。这对于速度影响恒大,所以我们需要尽量减少随机I/O的次数。
引入了区(extent)的概念,一个区就是在物理位置上连续的64个页。在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区为单位分配,甚至在表中的数据十分非常特别多的时候,可以一次性分配多个连续的区。虽然可能造成一点点空间的浪费,但是从性能角度看,可以消除很多的随机I/O,功大于过嘛!
段(segment)
InnoDB对B+树的叶子节点和非叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区。存放叶子节点的区的集合就算是一个段(segment),存放非叶子节点的区的集合也算是一个段。也就是说一个索引会生成2个段,一个叶子节点段,一个非叶子节点段。
默认情况下一个使用InnoDB存储引擎的表只有一个聚簇索引,一个索引会生成2个段,而段是以区为单位申请存储空间的。,一个区默认占用1M存储空间,对于不足以填满一个区的情况,提出了碎片(fragment)区的概念。也就是在一个碎片区中,并不是所有的页都是为了存储同一个段的数据而存在的,而是碎片区中的页可以用于不同的目的,比如有些页用于段A,有些页用于段B,有些页甚至哪个段都不属于。碎片区直属于表空间,并不属于任何一个段。所以此后为某个段分配存储空间的策略是这样的:
在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的。
当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间。
区的分类
空闲的区(FREE)现在还没有用到这个区中的任何页面。
有剩余空间的碎片区(FREE_FRAG)表示碎片区中还有可用的页面。
没有剩余空间的碎片区(FULL_FRAG)表示碎片区中的所有页面都被使用,没有空闲页面。
附属于某个段的区(FSEG)每一个索引都可以分为叶子节点段和非叶子节点段,除此之外InnoDB还会另外定义一些特殊作用的段,在这些段中的数据量很大时将使用区来作为基本的分配单位。
为了方便管理这些区,设计InnoDB的设计了一个称为XDES Entry的结构(全称就是Extent Descriptor Entry),每一个区都对应着一个XDES Entry结构,这个结构记录了对应的区的一些属性。