MySQL数据库InnoDB存储引擎Page页

前言

我们大多数时候,在操作数据库一般只关注如何保存或者获取到正确的数据,但是对于数据是以何种格式存储到磁盘里少有去了解。个人觉得理解这个过程有很大意义,于是顺带好奇对MySQL数据库InnoDB存储引擎中Page页进行探究。

一、Page是什么?

Page是InnoDB存储引擎磁盘管理最小单位,默认大小为16k。我们也可以将通过参数设置为4k、8k、16k。有个问题需要注意,是不能设置为5k或者6k,因操作系统页大小就是4k。Page还分类,在缓冲池里常见的类型有:索引页、数据页、Undo页、系统页等
以下是page的结构图,可见page是由7个部分组成

File Header
Page Header
Infimum 和Supremum Records
User Records
Free Space
Page Directory
File Trailer

File Header

file header的作用是用来记录页的一些通用信息,站用空间38个字节。
以下表格展示是file header组成部分

名称大小(字节)描述
FIL_PAGE_SPACE_OR_CHKSUM4存储页的checksum值,用于页的校验,校验页是否完整和损坏
FIL_PAGE_OFFSET4表空间中页的偏移值。如某独立表空间a.ibd的大小为1GB,如果页的大小为16k,那么总共有65536个页。FIL_PAGE_OFFSET表示该页在所有页中的位置,如果此表空间id为10,那么搜索页(10,1)就表示查找表a中的第二页
FIL_PAGE_PREV4当前页的上一个页,B+Tree的特性决定了叶子结点是双向链表
FIL_PAGE_NEXT4当前页的下一个页,B+Tree的特性决定了叶子结点是双向链表
FIL_PAGE_LSN8该值代表该页最后被修改的日志序列位置LSN,当系统宕机了在重启恢复应用日志阶段,如果redo log的lsn小于等于该值,就不需要重做redo log日志了
FIL_PAGE_TYPE2记录该页属于什么类型如索引页、数据页、Undo页、系统页等
FIL_PAGE_FILE_FLUSH_LSN8当InnoDB正常关闭,在刷新redo log和脏页后,会做一次完全同步的checkpoint,并将checkpoint的LSN写到表空间的FSP HEADER PAGE的FIL_PAGE_FILE_FLUSH_LSN变量中,启动后会拿该变量进行比较,判断是否正常关闭,是否需要故障恢复
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID4该值表示页属于哪个表空间

Page Header

page header表示页面的头部,用来记录数据页本身的专有信息,站用56个字节。
以下表格展示是 Page Header组成部分

名称大小(字节)描述
PAGE_N_DIR_SLOTS2在Page Directory中Slot的数量,初始值为2
PAGE_HEAP_TOP2堆中第一个记录指针
PAGE_N_HEAP2堆中的记录数,一共占用2字节,但是第15位表示行记录格式
PAGE_FREE2指向可重用空间的首指针
PAGE_GARBAGE2已标记为删除记录的字节数
PAGE_LAST_INSET2最后插入记录的位置
PAGE_DIRECTION2最后插入方向
PAGE_N_DIRECTION2一个方向连续插入记录的数量
PAGE_N_RECS2该页中记录的数量
PAGE_MAX_TRX_ID8修改该页最大事务ID
PAGE_LEVEL2当前页在索引树中的位置,0x00代表叶子节点。
PAGE_INDEX_ID8索引页的索引id

Infimum and Supremum Records

主要是用来限定User Records的边界,Infimum 记录的是比该页任何主键值都小的值,Supremum记录是比该页任何主键值都大的值,这两个值在页创建是被建立,并且在任何情况下不会被删除。

User Records

实际存储用户插入的行内容,每一行记录都有指向下一行的指针,是个单向链表结构。

Free Space

用来管理空闲空间,也是一个链表结构。如一条记录被删除后,该空间会被加入到空闲列表中。

Page Directory

page directory是页目录,作用当数据页加载到内存时,通过page directory进行二叉查找,快速找到行记录。

File Trailer

file trailer用来检测页是否完整。总共8个字节,前4个字节存储变量innodb_checksums,每次从磁盘读取一个页就是通过该变量来检测页的完整性。后4个字节存储变量innodb_checksum_algorithm用来控制检测checksum函数算法。

二、行记录格式

前面主要讲了page一些结构组成部分,但实际上用户插入记录的时候,存在page里是以行记录存储。在InnoDB里行记录格式有:compact、redundant、compressed、dynamic。

compact行记录格式

compact行记录格式结构如下图

变长字段长度列表NULL标志位记录头信息列1数据列2数据DB_ROW_IDDB_TRX_IDDB_ROLL_PTR

变长字段长度列表

变长字段长度列表是用来存储一行记录非null变长字段长度的列表,比如设置字段属性varchar(50),但实际存储数据长度有可能少于50,此时需要变长字段长度列表记录实际存储数据长度。
关于变长字段长度列表有以下两个规则:

  1. 若列的长度少于255字节,用1字节表示。
  2. 若列的长度大于255字节,用2个字节表示。

NULL标志位

null标志位主要记录列是否为null值,是用1表示,站用1个字节。

记录头信息

compact行格式记录头信息,站用5个字节,组成部分如下表格:

名称大小(字节)描述
()1未知
()1未知
deleted_flag1该行是否已被删除
min_rec_flag1为1,表示该行是预先定义最小的记录行
n_owned4该记录拥有的记录数
head_no13索引堆中,该条记录的排序记录
record_type3记录类型:000表示普通,001表示B+树节点指针,010表示infimum,011表示supremum,1xx表示保留
next_record16页中下一条记录的相对未知
total40该页中记录的数量

列数据

实际存储的数据列

隐藏列

隐藏列用户是查不到的,当InnoDB发现用户没有自定义主键或者没有合适数据列作为主键,此时会自己创建主键,DB_ROW_ID字段就是用来存放自主创建的主键。DB_TRX_ID表示事物ID,DB_ROLL_PTR表示回滚指针,它们的作用是用于事务回滚

行溢出

InnoDB的页大小为16k,总共16384个字节。那实际可以存储记录长度为多少时,会发生溢出?官方手册定义可设置varchar最大长度为65535,其实可以理解为所有varchar列总和为65535。这样不就超过页的大小?首先16384字节减去其他额外字段长度如回滚指针,事务ID等,实际存储长度还要少于16384。当存储记录长度为65535时,其实只保存varchar(65535)的前768字节的前缀数据,剩余的会存储在BlOB页。

redundant行记录格式

redundant是MySQL5.0之前老版本格式,MySQL5.0之后版本支持redundant格式是为了兼容老版本,本文不进行讨论。

compressed行记录格式

compressed行记录格式,存储的行数据会以zlib的算法进行压缩,适用于BLOB、TEXT、VARCHAR这种大长度类型字段。

dynamic行记录格式

dynamic行记录格式是现在mysql默认行记录格式,和compact基本一样,唯一区别是当发生行溢出时,数据页中只存放指向BLOB页的20个字节指针,BLOB页实际存储数据。

总结

本文简单介绍了MySQL数据库InnoDB存储引擎中Page页的内部结构和行记录格式。现在新版本默认行记录格式都是dynamic,和compact区别主要在于行溢出处理方式不同。此外我们也知道compressed是对行数据进行压缩的,对存放特别大的字段可以节省存储空间。

参考资料

MySQL技术内幕InnoDB存储引擎第2版

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星原始居民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值