上篇文章介绍了,表空间分为若干区,叶子节点和非叶子节点又分为不同的段,还有回滚段等,段里会存储碎片区不同数据页的集合和完全区的集合,碎片区是为了在数据刚存入表时候,存储不同段内的数据,当段内数据有32个碎片区时,会升级成为完整的区属于特有的段。
通过以上知识,知道了段分为若干个区,这些区大体可以分为四种类型:
这四种类型称为区的状态state。
再次强调一下FREE、FREE_FRAG、FULL_FRAG因为是碎片区,这是直属于表空间管理的,而最后FSEG是直接属于某个段的。
为了方便管理这些区,于是mysql创建了extent descriptor Entry,简称xdes enrty,每个区都对应一个XDES Enrty结构,这些结构记录了区的对应属性,结构分为四大部分:
到现在为止,我们可以捋一捋数据整个的插入段的过程了,及其这个过程中xdes entry发挥的作用是什么。
首先新建表的数据很少,页属于某个区,区又属于某个段,但若在数据很少的情况下就让这个区属于特定的段,显然是浪费时间和空间的。
插入数据,先看free_frag是否有空闲的碎片区,有的话直接存进去,没有则去申请free碎片区,然后把free碎片区升级为free_frag碎片区,当free_frag碎片区存储满的时候,则会吧free_frag升级为full_frag碎片区。现在的问题是你如何知道哪些是空闲碎片区,哪些是碎片区,哪些是full_frag无空闲碎片区呢,难道遍历吗?
答案肯定是no,这时候xdes entry的作用就来了,他吧这三个类型链接成三个不同的链表,所以就有了
这样我们查找的时候,只需要看free frag链表是否为空,不为空则插入到当前碎片区,为空则去free链表新增free碎片区,并且修改state字段,当free_frag充满之后,也会修改state字段,进入full_frag碎片区。
那什么时候进入fseg区呢?当数据占满32个零散页后,就会升级到属于某个特定段的区。
那还是回到之前的问题,如何区分属于哪个段呢,直接把整个链表属于哪个段?肯定不行,整个链表里面的零散区是只属于表空间管理,存着不同段的数据,这样直接放又如何区分哪个是叶子节点段,非叶子节点段数据呢?按sengment Id也不行,因为段里面有很多区,有的区可能还是空闲的,并不是当前段的所有区进入了full_frag五空闲碎片区才开始属于某个特定段,所以还要继续细分。。。fseg区细分为三个链表:
所以分析一下,当一个表里有一个聚簇索引,一个二级索引的时候,有两个索引,而一个索引会生成子叶节点段和非子叶节点段,所以有四个段,而一个段需要管理三个链表,所以有12个链表,再加上表空间结构直接管理的3个链表,所以为了管理这些段里的区,一共有15个链表,当数据进入当前端的时候,会先看not_free链表,直接吧数据插入当前的段,当not_free为空的时候,则会进去段的full链表。