概述
前面几节,我介绍了行记录,页,索引(B+)的结构,索引的叶子和非叶子节点都是由页构成的,页的大小有16k,可以存储满行记录。那么问题来了,一张表有多个索引,那这些索引又是怎么组织起来的呢,答案就是我们今天要讲的表空间,表空间真是描述了一张表怎么合理存储多个索引的,也就是表数据(索引即数据)。
表空间结构解析
1.表空间整体结构
1.表空间其实是一个文件,存在mysql安装时候的数据目录下面
2.每创建一张表,就会生成一个.idb文件,这个文件就是表空间文件
3.一个表文件中分为很多extend(区),每255个区是一个组
2.区结构解析
1.一个区一般是由64页组成,虽然索引的节点都是页组成的,如果按照16k为单位来分配,那么
在磁盘上一个表的数据都是分散的,会导致磁盘旋转频繁,也就是随机IO,所以按照区来分配
空间,一张表内容是连续存储的,也就是顺序IO,比较快(join表是不是就慢了,不在一个表空间)
2.表空间第一个组的第一个分区第一页是比较特殊的,也就是FSP_HDR类型的页,他存储一个表空间级别的一些
信息,还有当前组的所有区(256)的属性信息,其他组的第一个分区的第一页的页类型是XDES,他只存储当前组的
所有区的属性信息,也就是用来管理当前组的一些统计信息的
3. 表空间第一个组的第一个分区第二页是比较特殊的,也就是INODE类型的页,这个页只存储了表空间级别的信息
其它分组的页都没这个页。这个页存什么信息呢,存的是段的信息,什么是段?其实是索引有关的信息
3.段结构解析
1.段是存储在INODE页里面的,段是表空间级别的信息,那么为什么会有段呢?
a.表存储数据,按照mysql设计,其实就是存储索引,比如聚簇索引,叶子节点就是表数据了
b.索引是由页构成的,如果分配是按照页单元分配,那么B+树上相邻的页节点可能相离的物理距离非常远
那么这个时候加载相邻的两个页就要转动磁头了,那么就是所谓的随机IO,访问非常慢,索引按照页来
分配空间是不合理的。
C.一个分区大小是64*16k,如果按照区来分配空间,那么如果数据很小情况下,直接就以1M分配了
又太浪费空间了,所以采用了混合区和页的分配方式,也就是段
2.看到段结构,它其实数据部分是这些字段。
a.Fragment Array Entry 0-31是指向页的,也就是数据量小于32页,使用页来存储的
b.FREE链表,NOT_FULL链表,FULL链表是指向区的,直接分配区的空间存储表索引数据,当
Fragment Array Entry已经使用完后
4.索引和段关系图解析
1.一个索引会分配两个段,叶子节点和非叶子节点是分开存储的。
2.使用两个段来存储,是想要压缩叶子节点和非叶子节点,它们分别相邻页的距离
从而达到顺序IO的目的。这里有个原则是,叶子节点只会访问相邻的叶子节点,不会
访问到非叶子节点,所以分开存储达到更好的顺序IO效果
5.段和表空间关系图解析
1.段是一个索引的开始的地方,每当一个插入一条数据,先找到段,然后查找段的存储情况
如果数据量还未满32页,那么继续使用碎片区插入数据,否则直接申请单个区插入数据
2.段完全展示了数据库分配空间的一些细节,可以看到在设计上,为了节省空间使用碎片区,
为了顺序IO,大量数据之后采用区作为分配空间策略,叶子和非叶子节点分段储存
6.整体结构图