1. 区存在的意义
由于B+树的每一层中的页都是以双向链表的形式存在,如果以页为单位来分配存储空间,双向链表相邻的两个页之间的物理位置可能距离非常远。在范围查找(定位到最左边记录和最右边记录)的场景,沿着双向链表一直扫描便可查找到结果,由于双向链表中相邻两个页物理位置距离可能非常远,会产生随机IO,为了尽量让链表中相邻的页的物理位置也相邻,进行范围查询的时候可以使用所谓顺序IO,区的概念随之诞生。一个区在物理位置上表示连续64个页,在InnoDB中页的大小默认是16KB,因此一个区的便是1MB。当表中数据量大的时候,便不再以页为单位为某个索引分配空间,而是以区为单位分配,甚至在表中数据特别多的时候,可以一次性分配连续多个区,虽然可能造成一点点空间的浪费(数据不足以充满整个区),但从性能的角度而言,可以消除很多随机IO。
2. 段存在的意义
对于范围查询,本质是对B+树叶子节点中的记录进行顺序扫描,但如果不区分叶子节点和非叶子节点,把节点代表的页都申请到区中,范围查找效率大打折扣。InnoDB为了消除此种影响,对B+树的叶子节点和非叶子节点进行了区别对待,即叶子节点有自己独立的区,非叶子节点也有自己独有的区.存放叶子节点区的集合便是一个段,同理存放非叶子节点的区的集合也算是一个段,一个索引会产生两个段,一个叶子节点段(数据段)和一个非叶子节点段(索引段)。段其实不对应表空间中某一个连续的物理区域,而是一个逻辑上的概念,由若干个零散的页面以及一些完整的区组成。
3. 碎片区存在的意义
为了考虑以完整区为单位分配给某个段对于数据量较小的表太浪费存储空间的情况,InnoDB提出碎片区概念。在一个碎片区中,并不是所有的页都是为了存储同一个段的数据存在的,而是碎片区中的页可以用于不同的目的,比如有些页用于段A,有些页用于段B,有些页甚至哪个段都不属于。碎片区直属表空间,并不属于某一个段。所以此后为某个段分配内存空间的策略如下:
- 刚开始向表中插入数据,段是从某个碎片区以单个页面为单位分配存储空间。
- 当某个段已经占用32个碎片区页面之后,申请以完整的区为单位分配存储空间。