这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记
数据库的存储结构:页
磁盘与内存交互基本单位:页 InnoDB 将数据划分为若干个页,InnoDB中页的大小默认为 16KB 。
以页作为磁盘和内存之间交互的 基本单位 ,也就是一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。也就是说,在数据库中,不论读一行,还是读多行,都是将这些行所在的页进行加载。也就是说,数据库管理存储空间的基本单位是页(Page),数据库 I/O 操作的最小单位是页。一个页中可以存储多个行记录。
记录是按照行来存储的,但是数据库的读取并不以行为单位,否则一次读取(也就是一次 I/O 操作)只能处理一行数据,效率会非常低。
页结构概述
页a、页b、页c ... 页n 这些页可以 不在物理结构上相连 ,只要通过双向链表相关联即可。每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在它里边的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中 使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录 .
页的上层结构
另外在数据库中,还存在着区(Extent)、段(Segment)和表空间(Tablespace)的概念。行、页、区、段、表空间的关系如下图所示:
页的内部结构
页如果按类型划分的话,常见的有数据页(保存 B+ 树节点)、系统页、Undo 页和事务数据页等。数据页是我们最常使用的页。
数据页的 16KB 大小的存储空间被划分为七个部分,分别是文件头(File Header)、页头(Page Header)、最大最小记录(Infimum+supremum)、用户记录(User Records)、空闲空间(Free Space)、页目录(Page Directory)和文件尾(File Tailer)。
File Header(文件头) 和 File Trailer(文件尾)
File Header 描述页的通用信息
FIL_PAGE_SPACE_OR_CHKSUM 校验和,页头有 页尾也有,用来保证该页的数据一致性
FIL_PAGE_OFFSET 页号,标识当前页
FIL_PAGE_PREV 标识上一页
FIL_PAGE_NEXT 标识下一页
File Trailer
User Records(用户记录) 和 Infimum+Supremum(最大最小记录) 以及 Free Space(空闲空间)
Free Space
User Records
我们存储在数据库中的每一行数据按照指定的行格式,以单链表的形式存储在这个区域。
表中记录的行格式示意图
c1 c2 c3这三个列为我们自定义的列。
记录头信息的各个属性如下:
next_record 它表示从当前记录的真实数据到下一条记录的真实数据的地址偏移量,注意:最小记录的头信息中next_record指向本页用户记录的第一条,本页用户记录的最后一条记录的next_record指向最大记录。
Infimum+Supremum
比较记录的大小就是比较主键的大小
InnoDB规定的最小记录和最大记录都是由5字节大小的记录头信息和一个8字节大小的固定部分组成,如下图示
这两条记录不是我们自己定义的记录,所以他们并不在页的User Records区域,而是存放在Infimum+Supremum区域,如下图示
Page Directory(页目录) 和 Page Header(页头)
Page Directory
页目录分组的个数如何确定
页目录结构下如何快速查找记录
页目录的槽中存储的是每组主键值最大的记录。假设通过二分法确定该记录在槽3,因为记录是以单链表的形式存储,所以不能从后往前遍历,需要通过前一个槽 也就是槽2的next_record来找到当前槽的最小记录,然后再遍历。
Page Header
从数据页的角度看B+树
InnoDB行格式
我们平时的数据以行为单位来向表中插入数据,这些记录在磁盘上的存放方式也被称为行格式或者记录格式 。InnoDB存储引擎设计了4种不同类型的 行格式 ,分别是 Compact 、 Redundant 、 Dynamic(MySQL8默认) 和 Compressed 行格式。
Compact
变长字段长度列表
NULL值列表
明确表明非空的字段不会被记录在这个字段
记录头信息(参考上一节的第二小节)
记录的真实数据
Redundant---不重要
区别
字段长度偏移列表
记录头信息