不知不觉2022年已经结束了,没想到时间过得那么快,在这里祝大家新年快乐。
页是InnoDB管理存储空间的基本单位。
InnoDB为了不同目的实现了多种的不同类型的页,比如存储表空间头部的页、存放INODE信息的页等等。
但是我们比较关心的应该是存放表中记录的页,官方把这种存放记录的页称为索引页。
为了方便理解,下面把索引页称为数据页。
数据页大小为16KB,这16KB被划分成多个部分。
数据页被分为7个部分,各个部分是干啥用的?请看下图
我们存储的记录是按照行格式存储在User Records部分。
但是在一开始生成页的时候,并没有User Records部分,当插入一条记录的时候,会从Free Space部分申请一个记录大小的空间。
当Free Space空间完全被User Records部分代替完之后,就意味着这个页用完了,如果再插入一条数据,就需要申请新的页了。
在【MySQL】InnoDB记录存储结构有详细说到记录有信息。
但是这里主要说的是记录头的信息,先建一个表
CREATE TABLE page_demo(
c1 INT PRIMARY KEY,
c2 INT,
c3 VARCHAR(10000),
)CHARSET=ASCII ROW_FORMAT=COMPACT;
这是设置c1为主键,那么InnoDB就没有必要创建row_id列了。
并且指定了ASCII字符集以及COMPACT的行格式。
这一节主要讲述记录头信息的作用,因此可以简化一下行格式。
往表中插入数据
mysql> INSERT INTO page_demo VALUES(1, 100, 'aaaa'), (2, 200, 'bbbb'), (3, 300, 'cccc'), (4, 400, 'dddd');
Query OK, 4 rows affected (0.00 sec)
User Records部分的存储结构如下图所示
但是需要注意的是,这里把记录中的头信息和实际数据都用是十进制表示出来了,但是实际上是二进制位。
可以看见记录头有很多属性,那么各个属性代表什么呢?
delete_flag
:这个属性是标记当前记录是否被删除,占用1比特。
min_rec_flag
:B+树每层非叶子节点中的最小的目录项都会添加该标记。n_owned
:记录了该组有几条记录heap_no
:一条记录在堆中的相对位置
heap_no
比较小,在页面后面的记录比较大。heap_no
的值分别为2、3、4、5Infimun记录
)和最大记录(Supremum记录
)的heap_no
值,它们被称为虚拟记录或伪记录。Infimun记录
和Supremum记录
这两条记录的构造十分简单,都是由5字节大小的记录头信息和8字节大小的一个固定单词组成的。由于其heap_no最小,所以这两个记录放在堆的最前面。heap_no
是固定不变的,也就是值分配之后就不会发生改动了,即使被删除,值也不会发生变化。record_type
:这个属性表示当前记录类型。
next_record
:这个属性非常重要,它表示当前记录的真实数据到下一条记录的真实数据的距离。
delete_flag
就会被设置为1,并第二条记录的next_record
变为0,第一条记录的next_record
指向第三天记录next_record
的位置之所以在记录头和真实数据之间,**是因为这种向左读取就是记录头信息,向右读取就是真实数据。**前面说到变长字段长度列表和NULL值列表都是逆序存放的,这样可以使得记录中位置靠前的字段和它对应的字段长度信息在内存中距离更近,可以提高高速缓存命中率。如果想要查找某一条记录,并不会在链表中一个个遍历查找。
在设计InnoDB的时候,为我们的记录制作了一个类似图书目录的目录。
n_owned
记录该组有多少条记录。比如page_demo表中有6条数据,就会被分成2组。
那分组是这么分的呢?
例如,再向表插入12条记录
怎么查找记录呢?
初始情况下最低的槽就是low = 0, 最高的槽就是hight=4,比如要找主键为6的记录。
页面头部是存储书局页中记录的状态信息,比如数据页存储了多少条记录、Free Space在页面中的地址偏移量、页目录中存储了多少槽等。
文件头部描述了一些通用各个页的信息,比如页的编号,它的上下页是谁等等。
文件头部由固定38个字节组成。
FIL_PAGE_SPACE_OR_CHKSUM
:这个属性代表当前页面的校验和 (checksum)。啥是校验和?就是对于一个很长的字节串来说,我们会通过某种算法计算出一个比较短的值来代表这个很长的字节串,这个比较短的值就称为校验和。这样在比较两个很长的字节串之前,先比较这两个长字节串的校验和。如果校验和都不一样,则两个长字节串肯定是不同的,这样就省去了直接比较两个长字节串的时间损耗。FILE_PAGE_TYPE
:页的类型并且页是一个双向链表。
文件尾部是用来检测一个页是否完整,防止刷新的时有没有发生只刷新一部分的情况。
文件尾部由8字节组成,分为两个部分:
参考:
- 《MySQL是怎样运行的:从根儿上理解 MySQL》
- 【MySQL进阶】深入理解InnoDB数据页结构_小颜-的博客-CSDN博客