【InnoDB Page Structure】
页: InnoDB存储数据的基本单位,一个页可以存储16KB的数据
InnoDB的数据页的设计,有7个部分,分别是:
- File Header
File Header表示页的一些通用信息。一张表有上亿条数据,这些数据会分散在很多个不连续的页中存储。每个数据页的File Header部分都有上一个和下一个页的编号,所以所有的数据页会组成一个双链表。
- Page Header
(1) deleted_flag : 在记录头信息中,标志着数据已经被删除。这就以为着删除数据并不会将数据立即从磁盘中删除(因为删除磁盘之后,其他数据需要重排序,消耗性能。因此只是打上一个标志,这些数据会形成一个垃圾链表,这些数据属于可重用空间,如果后续有数据进来,可能会重用)
(2) next 16 bits : 指向下一条数据的指针或者说是偏移量,从下图中可以看到,我们的数据是按照主键从小到达排序的,形成了一个单向列表。
- Page Director - 页目录
Page Director可以理解成索引(有时间也被称为槽 - slots),不像其他的DBMS,InnoDB不需要为每个数据页的record创建slots,相反,InnoDB只保留了一个稀疏的目录,在一个完整的page中,每6个记录将会有个solts。
这些slots的排序
a. 将所有正常的记录,包括最大记录与最小记录,不包括已删除的记录划分为几个组
b. 每个组的最后一条记录(也就是最大的那一条记录)的头信息中的n_owned属性表示该页拥有多少条记录,也就是该组内共有几条记录
c. 将每个组的最后一条记录的地址偏移量单独提取出来按顺序存储到靠近页的尾部的地方
- Mysql的设计规则有条规则,对于最新记录所在的分组只能有一条记录,最大记录所在的分组可以有1~8条数据,剩余分组中记录条数在4~8条之间。
分组的步骤:
(1)初始情况下一个数据页里只有最小记录和最大记录两条记录,它们分属于两个分组
(2)之后每插入一条记录,都会从页目录中找到主键值比本记录的主键值大并且差值最小的槽,然后把该槽对应的记录的n_owned值加1,表示本组内又添加了一条记录,直到该组中的记录数等于8个
(3)在一个组中的记录数等于8个后再插入一条记录时,会将组中的记录拆分成两个组,一个组中4条记录,另一个5条记录。这个过程会在页目录中新增一个槽来记录这个新增分组中最大的那条记录的偏移量
现在我们可以想一想,我们如何从这个数据结构中快速的查询到一条数据。直观的感觉一定是使用二分查找
4个槽的编号分别是:0、1、2、3、4,所以初始情况下最低的槽就是low=0,最高的槽就是high=4。比方说我们想找主键值为6的记录,过程是这样的:
(1)计算中间位置,(0+4)/2 = 2,可以看到这个solts对应的值为8,因为 8 > 6,所以现在对应的high为2
(2)再次计算中间的位置,(0+2)/2 = 1,这时候slots对应的值为4,因为4 < 6,所以low=1,high不变
(3)现在可以确定,主键值为6的记录在slot2对应的组上,再从page中就可以查询到数据了
总结步骤:
(1)通过二分法确定该记录所在的槽,并找到该槽中主键值最小的那条记录 (2)通过记录的next_record属性遍历该槽所在的组中的各个记录