区(extent)
表空间中的页可以达到 2³²个页,实在是太多了,为了更好的管理这些页面, InnoDB 中还有一个区(英文名:extent)的概念。对于 16KB 的页来说,连续的**64**个页就是一个区,也就是说一个区默认占用 1MB 空间大小。
不论是系统表空间还是独立表空间,都可以看成是由若干个区组成的,每256**个区又被划分成一个**组。
第一个组最开始的 3 个页面的类型是固定的:用来登记整个表空间的一些整体属性以及本组所有的区被称为 FSP_HDR,也就是 extent 0 ~ extent 255 这 256 个区,整个表空间只有一个 FSP_HDR。
其余各组最开始的 2 个页面的类型是固定的,一个 XDES 类型,用来登记本组 256 个区的属性,FSP_HDR 类型的页面其实和 XDES 类型的页面的作用类似, 只不过 FSP_HDR 类型的页面还会额外存储一些表空间的属性。
引入区的主要目的是什么?我们每向表中插入一条记录,本质上就是向该表的聚簇索引以及所有二级索引代表的 B+树的节点中插入数据。而 B+树的每一层中的页都会形成一个双向链表,如果是以页为单位来分配存储空间的话,双向链表相邻的两个页之间的物理位置可能离得非常远。
我们介绍 B+树索引的适用场景的时候特别提到范围查询只需要定位到最左边的记录和最右边的记录,然后沿着双向链表一直扫描就可以了,而如果链表中相邻的两个页物理位置离得非常远,就是所谓的随机 I/O。再一次强调,磁盘的速度和内存的速度差了好几个数量级,随机 I/O 是非常慢的,所以我们应该尽量让链表中相邻的页的物理位置也相邻,这样进行范围查询的时候才可以使用所谓的顺序 I/O。
一个区就是在物理位置上连续的 **64 **个页。在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按照区为单位分配,甚至在表中的数据十分非常特别多的时候,可以一次性分配多个连续的区,从性能角度看,可以消除很多的随机 I/O。
段(segment)
我们提到的范围查询,其实是对 B+树叶子节点中的记录进行顺序扫描,而如果不区分叶子节点和非叶子节点,统统把节点代表的页面放到申请到的区中的话,进行范围扫描的效果就大打折扣了。所以 InnoDB 对 B+树的叶子节点和非叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区。存放叶子节点的区的集合就算是一个段(segment),存放非叶子节点的区的集合也算是一个段。也就是说一个索引会生成 2 个段,一个叶子节点段,一个非叶子节点段。
段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念。