先上结论:Innodb在idb文件中存储数据,无论是页还是记录,都是物理无关的,但是记录的物理无关只能在同一页中有效 (文末有解释)
实验1.
每条记录占用32B,包括回滚指针,版本号,记录头等.
页大小 16 KB
插入500条记录,再删除 id 在 1 ~ 49 的50条记录,最后再插入100条记录,比较idb文件
红色圈起来的是 主键,蓝色是记录头。如下图,每个记录头的 第三位都是0 (00 00 10 00 22 中的第一个0 表示 0000 ,其中第三位是0,表示没被删除)
删除主键在 1~49 范围的记录之后,主键在1~49范围的记录没有消失,只是记录头(方便起见,下面只画一个)的第三位被置为1 (2 表示 0010)
插入 100 条数据:原本被删除掉的 主键范围在 1 ~ 49 的记录空间被复用了,并且被替换成了 主键 50 ~ 99 的记录。(80 00 00 32 中的 32 是十六进制,表示成十进制是 50)
下列是具体的页数据:
插入500记录之后:
按照 页3 / 页4 / 页5 排序
三个节点(页):索引页 [页3] (1 -> 页4 , 221 -> 页5) / 记录 1 ~ 441 [页4] / 记录 221 ~ 500 [页5]
删除主键在范围1~50的记录之后:
三个节点(页):记录 3 ~ 500 [页3] / 记录 1 ~ 441 [页4] / 记录 3 ~ 220 , 221 ~ 500 [页5]
三个节点(页):上的Page Directory最靠近infimum和supremum两条记录可寻址范围 :
54 ~ 494 / 1 ~ 436 / 496 ~ 8
再插入100条记录后:
三个节点(页):索引 [页3] (50 -> 4, 276 -> 5) / 记录 50 ~ 500 [页4] / 记录 276 ~ 600 [页5]
解释:500条记录,虽然每条都是 32B, 但因为每一页还有管理页的信息存在,所以不能只用一页来存储完这 500 行。
对比测试:新建同样结构的表,插入400条数据,只存在一个 B-Tree 节点(页),并且 level 是 0,说明只有一个节点
删除100行记录之后,推测因为剩下的记录 450 只用一个页就能存储,所以记录发生了合并
最后没有索引节点,但是有三个数据叶节点,推测只有页 3 是有效的,因为 页3 的 Page Directory 可寻址范围是合法的 (50 ~ 500, 算上infimum和supremum及其n_owned)
再次插入100条数据之后,页3重新成为所有页,并且页4中原本被删除的记录留下的空闲空间被 主键范围为50 ~ 99的记录复用
整个过程如下图:注:主键是递增的
可以发现,从删除50条记录到再插入100条记录的过程中,数据页4被塞入了主键范围为442 ~ 500的记录,说明记录的指向关系还是受到物理上的制约的,因为PageDirectory寻址的偏移量就是基于当前页的,不能查找其他页的记录,如果 442 ~ 500 的数据不移到数据页 4 上,而数据页4想引用数据页5的数据的话,数据页4的PageDirectory是无法管理在数据页5上的记录的。
(关于PageDirectory :参考文章)
换句话说,就是数据节点里面的记录在物理上可以不按主键递增的规则分配,但逻辑上是顺序的
数据页之间逻辑上主键的大小必须是严格递增的。如下图
但在物理上,数据页在id文件中,不一定按照主键递增顺序放置:
数据页4逻辑上在数据页5之前,但物理上可以乱序,数据页5在数据页4之前
解释开头的一句话:记录在物理层面上的顺序无关只能限制在一个页内
解释:同一个页内的记录是可以不按主键顺序存放的,但是不能跨越到其他页上去
下图就是一个非法的跨页指向,记录只能指向同一个物理页中的记录,不能以其他页上的某条记录做为自己的下条记录,因为PageDirectory无法管理