从根儿上理解MySQL | InnoDB存储结构

目录

InnoDB记录结构

变长字段长度列表

NULL值列表

记录头信息

InnoDB页结构

Page Directory(页目录)

File Header(文件头部)

Page Header(页面头部)

File Trailer

总结


InnoDB是一个将表中的数据存储到磁盘上的存储引擎,而真正处理数据的过程是发生在内存中的,而MySQL中磁盘和内存交互的基本单位,页的大小一般为16KB。也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。

InnoDB记录结构

这里以Compact行格式来具体说明:

变长字段长度列表

MySQL支持一些变长的数据类型,比如VARCHAR(M)VARBINARY(M)等,变长字段中存储多少字节的数据是不固定的,所以我们在存储真实数据的时候需要顺便把这些数据占用的字节数也存起来。假设某个表中的c1c2c4列都是VARCHAR(10)类型的,存储的内容分别为‘aaaa’、‘bbb’、‘d’,并且各个列使用的是ascii字符集,所以每个字符只需要1个字节来进行编码,则存储的形式为:

image_1c9gbruvo504dlg1qsf19nbeu878.png-37kB

需要注意的是,各变长字段数据占用的字节数是按照列的顺序逆序存放,另外,变长字段长度列表中只存储值为非NULL的列内容占用的长度。

NULL值列表

将每个允许存储NULL的列对应一个二进制位,二进制位按照列的顺序逆序排列,值为1代表该列的值为NULL,为0代表不为NULL。假设c1c3c4这3个列的值都允许为NULL,其中c3c4的值都为NULL,所以这3个列对应的二进制位的情况就是,对应的NULL值列表就是06.

记录头信息

  • delete_mask

标记记录是否被删除,0代表未被删除,1代表已经被删除

注:被删除的记录会将delete_mask位设置为1并加入到垃圾链表中,而不是立即从磁盘中移除

  • min_rec_mask

标记B+树的每层非叶子节点中的最小记录,值为0表示不是B+树的非叶子节点中的最小记录

  • n_owned

每个组的最后一条记录(组内最大的那条记录),n_owned属性表示该组内共有几条记录。

  • heap_no

标记记录在页中的位置。注:最小、最大记录(伪记录)的heap_no分别为0、1,结构如下图所示:

  • record_type

标记当前记录的类型,0表示普通记录,1表示B+树非叶节点记录,2表示最小记录,3表示最大记录。

  • next_record

表示从当前记录的真实数据到下一条记录的真实数据的地址偏移量,实际上就是一个链表。注意:下一条记录指的是按照主键值由小到大的顺序的下一条记录,Infimum记录(最小记录) 的下一条记录就是本页中主键值最小的用户记录,而本页中主键值最大的用户记录的下一条记录就是 Supremum记录(最大记录)。从下图中可以看出,记录按照主键从小到大的顺序形成了一个单链表,最大记录的next_record的值为0,是单链表中的最后一个结点。

InnoDB页结构

Page Directory(页目录)

页目录就是将记录也制作成一个目录,将所有正常的记录(包括最大和最小记录)划分为几个组,每个组的最后一条记录的头信息中的n_owned属性表示该组内共有几条记录,然后将每个组的最后一条记录的地址偏移量单独提取出来按顺序存储到靠近页的尾部的地方,这个地方就是页目录,而页目录中的这些地址偏移量被称为

注意:对每个分组中的记录条数是有规定的:对于最小记录所在的分组只能有1条记录,最大记录所在的分组拥有的记录条数只能在1~8条之间,剩下的分组中记录的条数范围只能在是4~8条之间

在一个数据页中查找指定主键值的记录的过程分为两步

  1. 通过二分法确定该记录所在的槽(如想找主键值为6的记录,(0+4)/2=2 -> (0+2)/2=1 -> 2 ),并找到该槽中主键值最小的那条记录(拿到槽1对应的记录,该条记录的下一条记录);

  2. 通过记录的next_record属性遍历该槽所在的组中的各个记录。

File Header(文件头部)

描述了一些针对各种页都通用的一些信息,比方说这个页的编号是多少,它的上一个页、下一个页, 这个部分占用固定的38个字节。

对于上面的内容,值得注意的是FIL_PAGE_PREVFIL_PAGE_NEXT分别代表本页的上一个和下一个页的页号(只有索引页才有这两个属性),这样就通过建立一个双向链表把许许多多的页都串联起来,而无需这些页在物理上真正连着。也就是说,所有的数据页其实是一个双向链表

Page Header(页面头部)

用于记录数据页中存储的记录的状态信息,比如本页中已经存储了多少条记录,第一条记录的地址是什么,页目录中存储了多少个槽等等,这部分占用固定的56个字节,具体在这就不详述了。

File Trailer

File Trailer的设计是为了保证从内存中同步到磁盘的页的完整性,这个部分由8个字节组成,前4个字节代表页的校验和,后4个字节代表页面被最后修改时对应的日志序列位置(LSN)。在页的首部和尾部都会存储页中数据的校验和和页面最后修改时对应的LSN值,如果首部和尾部的校验和和LSN值校验不成功的话,就说明同步过程出现了问题。

总结

各个数据页可以组成一个双向链表,而每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在它里边儿的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录。

声明:本博客纯粹为读书笔记,如想详细了解MySQL相关知识请访问《MySQL是怎么运行的:从根儿上理解MySQL》原作者撰写资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值