MySQL存储引擎Innodb学习 | 青训营笔记

203 阅读4分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记

数据库的存储结构:页

磁盘与内存交互基本单位:页 InnoDB 将数据划分为若干个页,InnoDB中页的大小默认为 16KB 。

作为磁盘和内存之间交互的 基本单位 ,也就是一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。也就是说,在数据库中,不论读一行,还是读多行,都是将这些行所在的页进行加载。也就是说,数据库管理存储空间的基本单位是页(Page),数据库 I/O 操作的最小单位是页。一个页中可以存储多个行记录。

记录是按照行来存储的,但是数据库的读取并不以行为单位,否则一次读取(也就是一次 I/O 操作)只能处理一行数据,效率会非常低。

image-20220121101353113

页结构概述

页a、页b、页c ... 页n 这些页可以 不在物理结构上相连 ,只要通过双向链表相关联即可。每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在它里边的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中 使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录 .

页的上层结构

另外在数据库中,还存在着区(Extent)、段(Segment)和表空间(Tablespace)的概念。行、页、区、段、表空间的关系如下图所示:

image-20220121101807962

image-20220121101915676

页的内部结构

页如果按类型划分的话,常见的有数据页(保存 B+ 树节点)系统页Undo 页事务数据页等。数据页是我们最常使用的页。

数据页的 16KB 大小的存储空间被划分为七个部分,分别是文件头(File Header)、页头(Page Header)、最大最小记录(Infimum+supremum)、用户记录(User Records)、空闲空间(Free Space)、页目录(Page Directory)和文件尾(File Tailer)。

image-20220121102703273

File Header(文件头) 和 File Trailer(文件尾)

File Header 描述页的通用信息

image-20220121105531883

FIL_PAGE_SPACE_OR_CHKSUM 校验和,页头有 页尾也有,用来保证该页的数据一致性

FIL_PAGE_OFFSET 页号,标识当前页

FIL_PAGE_PREV 标识上一页

FIL_PAGE_NEXT 标识下一页

File Trailer

image-20220121110049471

User Records(用户记录) 和 Infimum+Supremum(最大最小记录) 以及 Free Space(空闲空间)

image-20220121110216100

Free Space

image-20220121110416883

User Records

我们存储在数据库中的每一行数据按照指定的行格式,以单链表的形式存储在这个区域。

表中记录的行格式示意图

c1 c2 c3这三个列为我们自定义的列。

image-20220121110941781

记录头信息的各个属性如下:

image-20220121111124355

image-20220121111427636

image-20220121111506138

image-20220121111544769

image-20220121111620005

image-20220121112222921

next_record 它表示从当前记录的真实数据到下一条记录的真实数据的地址偏移量,注意:最小记录的头信息中next_record指向本页用户记录的第一条,本页用户记录的最后一条记录的next_record指向最大记录

Infimum+Supremum

比较记录的大小就是比较主键的大小

InnoDB规定的最小记录和最大记录都是由5字节大小的记录头信息和一个8字节大小的固定部分组成,如下图示

image-20220121112001731

这两条记录不是我们自己定义的记录,所以他们并不在页的User Records区域,而是存放在Infimum+Supremum区域,如下图示

image-20220121112148774

Page Directory(页目录) 和 Page Header(页头)

Page Directory

image-20220121113053172

image-20220121113251018

image-20220121113510486

页目录分组的个数如何确定

image-20220121113700702

页目录结构下如何快速查找记录

image-20220121114053953

image-20220121114024893

页目录的槽中存储的是每组主键值最大的记录。假设通过二分法确定该记录在槽3,因为记录是以单链表的形式存储,所以不能从后往前遍历,需要通过前一个槽 也就是槽2的next_record来找到当前槽的最小记录,然后再遍历。

Page Header

image-20220121114613343

image-20220121114728337

从数据页的角度看B+树

image-20220121115003162

InnoDB行格式

image-20220121120336302

我们平时的数据以行为单位来向表中插入数据,这些记录在磁盘上的存放方式也被称为行格式或者记录格式 。InnoDB存储引擎设计了4种不同类型的 行格式 ,分别是 Compact 、 Redundant 、 Dynamic(MySQL8默认) 和 Compressed 行格式。

Compact

image-20220121120355881

变长字段长度列表

image-20220121120606439

image-20220121120810714

NULL值列表

image-20220121120959968

image-20220121121121708

明确表明非空的字段不会被记录在这个字段

记录头信息(参考上一节的第二小节)

记录的真实数据

image-20220121121236971

Redundant---不重要

image-20220121145753469

区别

字段长度偏移列表

image-20220121145901943

记录头信息

image-20220121150042706

Dynamic 和 Compressed

行溢出

image-20220121121537376

image-20220121145519940

image-20220121145535819

Dynamic 和 Compressed行格式

image-20220121145640984