Mysql之InnoDB数据页(索引页)结构解析
2020-09-24 11:16:36 4 举报
Mysql之InnoDB数据页(索引页)结构解析,如何通过主键值快速定位到要查找的记录,学习索引的必经之路
作者其他创作
大纲/内容
0
槽1
其他信息
next_record(16bit),表示下一条记录的相对位置
记录头信息(5字节)
2
no_owned
min_rec_mask(1bit),B+tree每层非叶子节点的最小记录都会添加此标记
这4条记录是一个分组
'gggg'
这1条记录是一个分组
300
min_rec_mask
记录2
page_demo数据表行格式简化示意图
10
·
head_no
roll_pointer / DB_ROLL_PTR
100
1
delete_mask
c1列的值
5
InnoDB为了不同的目的而设计了不同类型的页,如Undo日志页、Insert Buffer位图、系统页、事务系统数据、溢出页、数据页,我们这里主要分析的是我们把用于存放数据记录的页索引页也叫数据页(FIL_PAGE_INDEX),也就是如何通过主键值快速定位到要查找的记录,也是学习索引需要了解的知识点;页是InnoDB管理存储空间的基本单位,一个页的大小一般是16KB
数据页中的infimum+supremum部分(见图1)虚拟行记录,head_no的值分别为0和1,位置在所有记录中最靠前
记录1
NULL值列表
User Records(大小不确定)
c2列的值
最大记录
'llll'
'iiii'
用户记录(实际存储的行记录内容,按照指定的行格式存储如compact行格式)
记录的真实数据
'dddd'
7
5个槽的编号为0、1、2、3,最低槽low=0,最高槽high=3。使用二分法查找,如查找数字主键值为6的记录:1. 计算中间槽(0+3)/2=1,槽1对应的主键值是4,4<6,设high=3,low=12. (1+3)/2=2,槽2对应的主键值为8,8>6,所以确定主键值6的记录在槽2中,从主键为5的记录开始遍历,直到找到主键为6的记录为止
supremum
--图3--
32
next_record
record_type
Page Directory(大小不确定)
28
3
不论我们怎么对页中的记录做增删改操作,InnoDB始终会维护一条记录的单链表,链表中的各个节点是按照主键值由小到大的顺序连接起来的
列1c1的值
c3列的值
记录3
infimum
--图5--
这一条记录是一个分组,no_owned表示该组内拥有多少条记录(最小记录的分组只能有1条记录)
注:当前记录的真实数据到下一条记录的真实数据的地址偏移量
记录4
这5条记录是一个分组
'kkkk'
--图4--
'cccc'
记录n
最小记录
1100
200
400
这5条记录是一个分组(最大记录所在的分组记录条数在1~8条之间,剩下的分组记录条数范围只能在4~8条之间)
页->槽->记录
每插入1条记录,从Free Space中申请1个记录大小的空间,划分到User Records部分,直到Free Space完全被User Records部分替代(此时页使用完了,再有新记录去申请新的页)
9
列名
c1(int)(主键)
4
c2(int)
c3 VARCHAR(10000)
aaaa
bbbb
cccc
dddd
将每个组中的最后一条记录的地址偏移量提取出来,按顺序存储到靠近页的尾部的地方,这就是Page Directory页目录(见图1)页目录中的这些地址偏移量就称为槽(slot)
Page Header(56字节)
'ffff'
当插入更多记录:
11
record_type(3bit),表示当前记录的类型;0代表普通记录,1代表B+tree非叶节点记录,2代表最小记录,3代表最大记录
6
1200
900
'bbbb'
-111
自定义列
64
注:下一条记录并不是插入顺序的下一条记录,而是按照主键从小到大的顺序的下一条记录
每个槽对应的记录按照主键从小到大排列
'aaaa'
n_owned(4bit),表示当前记录拥有的记录数
槽0
页目录Page Directory
--图1--
文件头部(页的一些通用信息,如一页有多少条记录、多少个槽)
文件尾部(校验页是否完整)
预留位2(1bit)
前4个字节代表页的校验和,后4个字节代表页面被最后修改时对应的日志序列位置(LSN)为保证从内存中同步到磁盘的页的完整性,在页的首部File Header有FIL_PAGE_SPACE_OR_CHKSUM存储页的校验和,首部和尾部还会存储页面最后修改时对应的LSN值,每当一个页面在内存中修改了,尾部在同步之前就要把它的校验和File Trial算出来,如果首部和尾部的校验和以及LSN值校验不成功的话,就说明同步过程出现了问题。
变长字节长度列表
不是非叶子节点的最小记录时,为0
Infimum+supremum(26字节)
所以在一个数据页中查找指定主键值的记录的过程分为两步:1. 通过二分法确定该记录所在的槽,并找到该槽所在分组中主键值最小的那条记录。2. 通过记录的next_record属性遍历该槽所在的组中的各个记录。
存储记录的行格式示意图(下图为compact行格式)Compact行格式的详细结构解析见我的另外一个文件《Innodb记录结构---Compact行格式》
600
--图2--
最小记录和最大记录(两个虚拟的行记录)
'eeee'
1byte/字节=8bit/位(二进制位)
File Header(38字节)
假如删除了第2条记录,会发生的变化为:1. 第2条记录并没有从存储空间中移除,而是把该条记录的delete_mask值设置为1(当数据页中存在多条被删除掉的记录时,这些记录的next_record属性将会把这些被删除掉的记录组成一个垃圾链表,以备之后重用这部分存储空间)。2. 第2条记录的next_record值变为了0,意味着该记录没有下一条记录了。3. 第1条记录的next_record指向了第3条记录。4. 最大记录的n_owned值从5变成了4
槽2
8
500
'hhhh'
分组步骤:1. 初始情况下一个数据页里只有最小记录和最大记录两条记录,它们分属于两个分组。2. 之后每插入一条记录,都会从页目录中找到主键值比本记录的主键值大并且差值最小的槽,然后把该槽对应的记录的n_owned值加1,表示本组内又添加了一条记录,直到该组中的记录数等于8个。3. 在一个组中的记录数等于8个后再插入一条记录时,会将组中的记录拆分成两个组,一个组中4条记录,另一个5条记录。这个过程会在页目录中新增一个槽来记录这个新增分组中最大的那条记录的偏移量。
Innodb数据页(索引页)结构为7个部分
记录的额外信息
我发现一个问题:如果表中没有主键怎么形成单链表呢 ?如果没有主键InnoDB会在表中选一个unique键作为主键,如果没有定义unique键,InnoDB会默认生成一个row_id的隐藏列作为主键(这个在我另外一个文件《Innodb记录结构---Compact行格式》中有讲到)
File Trial(8字节)
列2c2的值
空闲空间(页中尚未使用的空间)
这些为记录
delete_mask(1bit),标记该记录是否被删除;0代表未删除,1代表记录被删除
数据页中的User_Records部分(见图1)
transaction_id / DB_TRX_ID
700
'jjjj'
Free Space(大小不确定)
每个数据页的File Header部分都有上一个和下一个页的编号(FIL_PAGE_PREV和FIL_PAGE_NEXT),所以所有的数据页会组成一个双链表
第1条记录真实数据的地址向后找32个字节便是第2条记录的真实数据
预留位1(1bit)
隐藏列(引擎自动生成)
800
按照主键从小到大顺序形成了一个单链表,最大值记录的next_record=0说明最大记录没有下一条记录了
页面头部(数据页的一些专有信息,比如页的编号是多少,上一页下一页是谁)
12
页面目录(页中某些记录的相对位置)
槽3
--图6--
1000
head_no(13bit),表示当前记录在记录堆中的位置
列3c4的值
0 条评论
下一页