我们在上篇文章介绍了一条记录的结构,本篇介绍它的上一层(乘放记录的盒子)-----索引页的结构.
1. 索引页结构速览
索引页(16KB)被分为7个区域,有的区域存储空间确定,有的不确定.如下图:
2. 记录的存储
1. 记录存储概述
记录存储在用户记录区,每向表中插入一条记录,就会向空闲区申请一块空间,存储该记录对应的行格式. 当空闲区空间使用完毕,意味着该页存满了.会申请新的页.为了下文叙述方便,我们先建立一个表,针对该表进行分析.
show tables;
create table page_demo(
c1 int,
c2 int,
c3 varchar(10000),
primary key (c1)
)charset=ascii row_format =compact ;
/*插入数据*/
insert into page_demo values (1,100,'aaaa'),(2,200,'bbbb'),(3,300,'cccc'),(4,400,'dddd');
select * from page_demo;
c1 c2 c3
1 100 aaaa
2 200 bbbb
3 300 cccc
4 400 dddd
2. 记录在页面中的组织形式
上文简单介绍了一下一条记录是怎么存入页面的.各条记录亲密无间的排列在用户记录区,看起来"万事大吉".但…是…,魔鬼隐藏在细节里.例如,如何快速的找到一条记录,遍历整张表吗?显然不是.我们需要将紧密排列在一起的记录内部的位置关系用某种数据结构结实出来,这种数据结构就是B+树索引.而B+树索引的构建需要借助每条记录的记录头信息
记录头信息
删除位:该条记录是否删除,1删除
min_rec_flag:
n_owned:
heap_no:该条记录在页面堆中的相对位置.
mysql中,什么是堆呢?
一条条紧密排列的记录称为堆.
Infimum(下确界)记录和supremum(上确界)记录
先加入的用户记录,会分配一个较小的heap_no,用户记录区第一条记录的heap_no号为2,0和1哪去了呢?答:分给Infimum(下确界)记录和supremum(上确界)记录了.这两条记录在页面中单独分配一个区域(26字节,七个区域之一)存储,Infimum表示该页最小主键值,由系统指定,同理,supremum表示该页最大主键值.
结构
案例对应的存储结构
我们在上文案例向表中插入了四条数据,存储结构如下图所示
next_record指向记录头信息与真实数据之间的位置,由于变长字段长度列表与控制列表逆序存放,记录靠前的字段和他对应的字段长度信息在内存中的距离更进,可能会提高高速缓存的命中率
删除记录2后的存储结构变化
红色为变化
页目录
现在,通过按照主键大小形成的记录链表(相当于根据主键排序),如果需要找到某一个值,可以从infimum记录开始,遍历查找.如果记录很多呢?使用目录.
创建目录的方法
首先将记录分为几个组,每个组的最后一个记录为该组组长,器n_owend记录该组记录有多少.组长的位置在页的末尾,用一个槽(2Byte)标记出,所有的槽在按照地址偏移量递增的顺序排列就形成了记录.如上图,分为两个组,第一组只有一条记录.
目录创建的规则
- Infimum分组最多一条,Supremum最多八条
- 其余4-8条
- 当插入时,选比带插入记录主键值大,但差值最小的槽作为待插入分组,该组组长的n_owned+1.如果带插入分组已经为8,拆分为两个组.第一个组四条,第二个组5条,加一个槽,指向4个的那个分组.
记录插入与查找举例
12条记录依次插入,页面结构如下
查找时,由于槽连续排列,且有序,使用二分查找.找到组长的位置,组长前面的组长的位置的下一条消息就是本组第一条消息,遍历本组即可.例如找到t5 id=5,low=0,heigjt=2,找到中间 mid=1,中间槽指向组长id为4,所有low=1,height-low=1,所有height所指即为本组组长,low所指下一个即为本组第一个.
3. 常见问题
1.为什么记录被删除,不会从硬盘中移除,而是在记录头中用删除标记未标记.
移除需要在磁盘上重新排列其它记录,耗费性能.删除位置一后,加入垃圾 链表重复使用.