《Mysql是怎样运行的》读书笔记二
一、InnoDB的表空间(存放InnoDB页)
关于系统表空间和独立表空间自行百度
1.1页面类型
InnoDB是以页为单位管理存储空间,聚簇索引和二级索引以B+索引的形式保存到表空间,而B+树的节点就是数据页,该页的类型为FIL_PAGE_INDEX,除了存放索引页面类型外,Innodb还有若干不同类型的页面
1.2页面通用部分
- FileHeader:记录页面的一些通用信息
- File Trailer:校验页是否完整,保证从内存到磁盘刷新时内容的一致性
FileHeader重温
1.3独立表空间结构
区(extent)
表空间中的页太多,InnoDB提出用区(extent)。对于16kb的页,连续64个页就是一个区,即一个区默认占用1MB空间大小,无论是系统表空间还是独立表空间,都可以看作由若干区组成,每256个区又被划分一个组
为什么要引入区,一个区是物理位置上连续的64个页,在表中数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配,而是按照区为单位分配。分区的目的也很明确,就是为了消除随机I/O。B+树链表中相邻的页的物理位置可能相差很远,产生所谓的随机I/O
由上图可得,
- 表的第一个组最开始的3个页面类型是固定的
- FSP_HDR:用于登记整个表空间的一些整体属性以及本组所有的区(即0~255)这256个区的属性,整个表空间只有一个FSP_HDR
- IBUF_BITMAP类型:这个类型的页面存储本组所有的区的所有页面关于INSERT BUFFER的信息
- INODE类型:这个页面类型存储了许多称为INODE的数据结构
- 表的其余组最开始的2个页面类型是固定的
- XDES类型:即extent descriptor,用来登记本组256个区的属性
- IBUF_BITMAP
断(segment)
分区为了消除随机I/O,分段的原因呢?
范围查询,其实就是对B+树叶子节点的记录进行顺序扫描,如果不区分叶子节点和非叶子节点,统统把节点页申请到区,扫描的效果会很差。索引InnDB对B+树的叶子节点和非叶子节点进行了区别对待。
- 叶子节点有自己独特的区。存放叶子节点的区的集合即为一个段 (叶子节点段)
- 非叶子节点也有自己的区。存放非叶子节点的区的集合即为一个段 (非叶子节点段)
碎片区(属于表空间,不属于如何一个段)
段是以区作为分配单位(即1MB),但是为了零星的几个页而甚至几条记录分配一个区,显然太浪费存储空间,所以InnoDB提出了碎片区的概念,即一个碎片区中,并不是所有页都是为了存储同一个段的数据而存在,而是碎片区中的页可以用于不同的目的,(有些用于段A,有些用于段B)。
所以之后段的分配存储空间的策略:
- 在刚开始向表中插入数据的时候,段是从某个碎片区以单个页面为单位来分配存储空间的。
- 当某个段已经占用了32个碎片区页面之后,就会以完整的区为单位来分配存储空间。
区的分类(4类)—》对应区的4种状态
- 空闲的区:现在还没有用到这个区中的任何页面,属于表空间
- 有剩余空间的碎片区::表示碎片区中还有可用的页面。
- 没有剩余空间的碎片区:表示碎片区中的所有页面都被使用,没有空闲页面。
- 附属于某个段的区。
XDES Entry(Extent Descriptor Entry)
为了管理这些区,每个区对应着一个XDES Entry结构
XDES Entry 是一个40个字节的结构,大致分为4个部分,各个部分的释义如下:
- Segment ID
每一个段都有一个唯一的编号,用ID表示,此处的 Segment ID 字段表示就是该区所在的段。当然前提是该区已经被分配给某个段了,不然的话该字段的值没啥意义。
- List Node (这个部分可以将若干个 XDES Entry 结构串联成一个链表)
如果我们想定位表空间内的某一个位置的话,只需指定页号以及该位置在指定页号中的页内偏移量即可。所
以:Pre Node Page Number 和 Pre Node Offset 的组合就是指向前一个 XDES Entry 的指针
Next Node Page Number 和 Next Node Offset 的组合就是指向后一个 XDES Entry 的指针。
-
State
可选的值就是我们前边说过的那4个,分别是: FREE 、 FREE_FRAG 、 FULL_FRAG和 FSEG 。
-
Page State Bitmap(16字节)
这个部分共占用16个字节,也就是128个比特位。我们说一个区默认有64个页,这128个比特位被划分为64个部分,每个部分2个比特位,对应区中的一个页。比如 Page State Bitmap 部分的第1和第2个比特位对应着区中的第1个页面,第3和第4个比特位对应着区中的第2个页面,依此类推, Page State Bitmap 部分的第127和128个比特位对应着区中的第64个页面。这两个比特位的第一个位表示对应的页是否是空闲的,第二个比特位还没有用。
XDES Entry链表
插入一条数据,既要往聚簇索引还要往该表的所有二级索引的B+树插入数据,但Index页之间的空间不一定在物理空间连续,所以会产生随机I/O,所以有了区的概念,一个区内开辟连续的64个页,这样不管是插入数据还是查询修改,都只是顺序I/O,效率会更高。段的出现,将叶子节点(页)和非叶子节点(页)所在的区做出划分,更方便了数据操作的效率,我们插入一条数据,不仅要在叶子节点进行插入,还要再非叶子节点插入数据,这样分段管理雀氏提升了一定的性能。
既然这么方便了,为什么还要引入XDES Entry来管理?
想提高向表插入数据的效率,又不至于数据量少而浪费表空间。哦,原来是担心随意开辟区(1MB大小而浪费表空间)