mysql学习笔记01

104 阅读5分钟

本文章是学习《MySQL是怎样运行的:从根儿上理解MySQL》一书的学习记录

第五章

页是InnoDB存储引擎为了管理数据而做。是InnoDB存储数据的基本单位,一般大小为16kb。页有多种,分别用于不同的作用,本章主要介绍了存储数据的数据页。

页结构

页的结构,大体可以分为7部分,这里直接使用图来展示

image.png

File Header

记录数据页的信息,比如页号,所在空间等。File Header有上一页的页号和下一页的页号这两个字段,通过这两个字段,可以形成页的链表,这样页直接就能连接起来,无需在物理结构上实现连续。不是所有的页类型都有这个结构。

Page Header

记录页中数据的统计信息也就是存储记录的状态信息。

Infimum Supremum

最小记录和最大记录 这是两个虚拟记录。用于做标记使用。具体的用法在后面写。

User Records

用户记录,用于存储用户实际操作时的记录

Free Space

未使用的空间,当用户要存储数据要申请空间时会从这个空间中申请。

Page Directory

页中的记录是分组的,Page Director会记录每个分组的最后一个记录的位置,用于快速定位。

File Tail

文件尾部,该部分是用于校验页信息是否完整的,防止数据从内存导入到磁盘的时候发生中断这种情况。

页结构是怎么结合的

为了真正搞懂上面七部分的作用,下面将会详细说一下各部分之间是怎么组合使用的。

首先插入一行数据的时候会逐渐申请未使用的空间,使其变为实际存储的空间,Free Space 到 User Records。 行数据也有专门的字段用来记录一些信息,在存储的时候会按照主键的大小来进行排序。

行数据字段有几个感觉比较重要的点说一下:

  1. delete_mask,用来记录这条数据是否删除了,也就是当我们执行delete操作的时候并不会立刻将数据从磁盘中删去,而是改变这个字段。被打上标记的字段会形成一个链表(垃圾链表),其所占用的空间被称为‘可重用空间’。在之后的数据新增操作的时候就可能会占用掉这个空间。
  2. heap_no,用来记录这行数据在页中的位置也就是第几个。
  3. next_record,记录了当前记录的真实数据到下一个记录的真实数据的偏移量。通过这样设计,记录直接就能形成链表结构了。

最大记录和最小记录是自动添加到页面中的,不是用户控制的,所以也被称为伪记录。这两条记录占用了heap_no的前两位数字0和1,我们插入的数字只会是从2开始。最小最大数据伪记录同时分别是页中记录链表的开头和结尾。

插入完数据后我们总会不可避免的要去查询,在实现上我们可以想到,由于有链表的存在我们可以一个个地查找记录直到找到我们要找的数据为止。看起来很好,但仔细一想,这样做查询的效率是不是有点慢?所有为了提高查询的效率InnoDB对页中的数据进行了分组操作。我们可以先定位数据在哪个组里,再快速定位到具体的数据。

所以页目录的作用就是为了记录每个分组的位置未设置的。页目录中有槽位来记录位置信息,每个槽位都会指向该分组的最后一个记录(该组的最大记录)。

每页分组的槽位设置是这样的:

  1. 最小记录和最大记录分别在两个不同的页目录中,最小记录在的分组只有自己,最大记录在的分组可以有1~8个。
  2. 插入数据时会找到主键值比本记录大并且差值最小的槽位,然后向该组插入该数据,直到该组数据超过8个。
  3. 如果超过8个就会分裂,一个分4个记录,另一个分5个记录。

查询的时候是这样查询的:

  1. 使用二分法计算主键值的大小找到查找值应该在哪个组中。
  2. 因为槽对应的是该组最后一行记录,所以为了遍历数据会从前一个槽中找到前一组的最后一行记录,然后就能从头遍历该组数据了。

存储完页信息后,mysql会汇总这些信息比如第一条记录地址是什么,槽数有多少等,这些信息回存储在页面信息Page Header中(适用于数据页)。

除了PageHeader这种记录数据页的信息外还有记录各种页通用信息的文件头部文件(File Header),这里有前一页的信息和后一页的信息,这样就能将页以链表的形式连接起来了。

mysql在处理的时候会现将也数据存储在内存上,等合适的时机到来后再写入磁盘中,为了防止写入到磁盘一半就没了这种情况,增加了File Trailer这个部分来校验内容。