数据页

InnoDB数据页默认为16KB,该大小只能在初始化数据目录时修改,一旦初始化后,将无法再更改。

行格式

COMPACT

变长字段长度列表 NULL值列表 记录头信息 隐藏列 列1的值 ···
  • 变长字段长度列表:当表中存在变长字段,如varchar,该字段存储变长字段的实际长度,并按照列顺序的逆序存放(列n ··· 列1的长度)。
  • NULL值列表:当表中有允许NULL的列时存在该字段,使用二进制方式按列逆序记录。1为是NULL。
  • 记录头信息:固定5字节,40位来描述记录的一些属性。

特殊的,如果使用定长字段如char,但使用的字符集是变长编码的,如utf8,则该字段长度也会存储在变长字段长度列表中。
一个数据页16KB,如果行数据超过了这个大小,会使用溢出页存储,即该行的最后20个字节记录下一页的地址,下一页存储剩余的数据。

DYNAMIC

5.7默认行格式,大概结构与compact差不多,但是将行的所有真实数据都存在溢出页中,行只存溢出页的地址。

隐藏列

mysql为每行记录添加的列。

列名 必须 空间/字节 描述
DB_ROW_ID 6 行id,唯一标识一行记录
DB_TRX_ID 6 事务ID
DB_ROLL_PTR 7 回滚指针

DB_ROW_ID仅表没有指定主键,且没用非空唯一的字段时才会创建。

数据页结构

数据页结构

名称 中文名称 空间大小(字节) 描述
File Header 文件头部 38 页通用信息
Page Header 页头部 56 数据页专有信息
Infimum+Supremum 页中最小和最大记录 26 两个虚拟记录
User Records 用户记录 不确定 用户存储的记录
Free Space 空闲空间 不确定 页中未使用的空间
Page Directory 页目录 不确定 页中某些记录相对位置
File Trailer 文件尾部 8 校验页的完整性

每次插入记录时,会从空闲空间申请一个记录大小的空间,划分到用户记录,当空闲空间全被使用,代表页用完了。

数据行头信息

名称 大小(比特) 描述
预留位1 1 未使用
预留位2 1 未使用
deleted_flag 1 删除标记
min_rec_flag 1 B+树中每层非叶子节点最小的目录项记录会添加该标志
n_owned 4 页面记录分为组,组长记录的该值是组员数量,组员记录该值为0
heap_no 13 当前记录在页面堆中的相对位置
record_type 3 记录类型;0-普通;1-B+树非叶子目录;2-最小;3-最大
next_record 16 下一条记录相对位置
  • deleted_flag:当一条记录被标记删除时,该记录的空间可被重用,且放入垃圾链表。不直接删除是为了减少删除后的整理消耗。
  • min_rec_flag:叶子节点的该值均为0。
  • n_owned:该组的组员数量,详细见下文页目录
  • heap_no:用户记录紧凑的排列在一起,构成记录堆。后面的记录比前面的记录该值大1,且每页有自动添加的Infimum和Supremum隐藏记录,分表代表存储页中的最小、最大记录(根据主键比较),其该值分别为0和1。注意,Infimum和Supremum只是相当于链表的一个空的Head和Tail,并不存储真正极值记录的信息。
  • next_record:下一条记录(主键大小的下一个)的地址,即B+叶子节点中的链表组成。同时页中Infimum的该值指向该页主键最小的记录,页中主键最大的记录的该值指向Supremum记录。在删除记录时,该值也会同步更新

    页目录

    在页中查询某个记录时,从最小记录遍历查找,时间复杂度O(n),为了降低复杂度,使用分组概念。

页中记录,分为多个组,每个组的最后一个记录为组长,其头信息中的n_owned储存该组的组员数量。
在查找时,先根据组进行二分查找确定在哪个组,再到具体的组内进行遍历查找,有点跳表的思想。

在页靠近尾部的地方有着页目录空间,提取组长的地址偏移量作为槽,,即每个槽都指向每个组的组长。
默认有两个槽,Infimum和Supremum。前者n_owned固定为1,后者不定。
每个组的成员数量在4-8之间,如果超过8,会新增一个槽,即新建一个分组进行对半分。

页头部

用于存储各种状态信息。

状态名称 占用空间大小 描述
PAGE_N_DIR_SLOTS 2 页目录中槽的数量
PAGE_HEAP_TOP 2 还没使用的空间最小地址
PAGE_N_HEAP 2 第一位标识是否为紧凑型记录;剩余15位标识本页堆中记录数量,包括标记为已删除的记录
PAGE_FREE 2 已删除记录链表头节点记录在页面的偏移量
PAGE_GARBAGE 2 已删除记录占用的字节数
PAGE_LAST_INSERT 2 最后插入记录的位置
PAGE_DIRECTION 2 记录插入的方向
PAGE_N_DIRECTION 2 一个方向连续插入的记录数量
PAGE_N_RECS 2 页中用户记录的数量
PAGE_MAX_TRX_ID 8 修改当前页的最大事务id
PAGE_LEVEL 2 当前页在B+树所在层级
PAGE_INDX_ID 8 索引ID,表示当前页属于哪个索引
PAGE_BTR_SEG_LEAF 10 B+树叶子节点段的头部信息,仅在B+树根页面中定义
PAGE_BTR_SEG_TOP 10 B+树非叶子节点段的头部信息,仅在B+树根页面中定义

文件头部

固定占用38字节,数据页的第一个组成部分,用于描述页的部分信息。

状态名称 占用空间大小(字节) 描述
FIL_PAGE_SPACE_OR_CHKSUM 4 页的校验和
FIL_PAGE_OFFSET 4 页号
FIL_PAGE_PREV 4 上一页页号
FIL_PAGE_NEXT 4 下一页页号
FIL_PAGE_LSN 8 页面最后修改时对应的日志序列号
FIL_PAGE_TYPE 2 页类型
FIL_PAGE_FILE_FLUSH_LSN 8 仅在系统表空间的第一个页中定义,代表文件至少被刷新到了对应的LSN值
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 4 页属于哪个表空间

文件尾部

8个字节,为了防止数据页刷盘时意外断电的完整性校验。
前四个字节位数据页校验和,与文件头中的FIL_PAGE_SPACE_OR_CHKSUM一致,在刷盘时,头部的FIL_PAGE_SPACE_OR_CHKSUM首先被刷到磁盘,如果正常刷完,尾部的校验和也会一并刷进去。如果刷一半,会造成头部和尾部的校验和不一致,代表刷盘过程出现意外。
后四个字节对应最后修改时对应的LSN的后四个字节,与文件头的FIL_PAGE_FILE_FLUSH_LSN后四个字节一致。同样用于校验页的完整性。