第05章-盛放记录的大盒子-InnoDB数据页结构

页是InnoDB管理存储空间的基本单位,默认大小16KB。

InnoDB设计了多种不同类型的页。

页的类型 #

下表列出了InnoDB的数据页结构:

英文名称中文名称描述
File Header文件头部页的通用信息。
Page Header页面头部数据页转悠的一些信息。
Infimum + Supremum最小记录和最大记录虚拟记录
User Records用户记录用户存储的记录内容
Free Space空闲空间页中尚未使用的空间
Page Directory页面目录页中记录的相对位置
File Trailer文件尾部页的校验信息
一开始生成页的时候,并没有User Records部分,每当插入一条记录时,都会从Free Space中分配一块空间,并将这个空间划分到User Records中。

记录 #

记录头信息记录了该记录的一些基本信息,其中重要的有:

名称描述
deleted_flag标记该记录是否被删除
min_rec_flag标记该记录是否是最小记录-B+树中每层非叶子节点中的最小的目录项记录都会添加该标记。
heap_no记录在页中的位置
next_record指向下一条记录的位置
record_type记录类型,包括普通记录、最小记录、最大记录、B+树非叶子节点记录等。
任何用户记录都比Infimum记录大,任何用户记录都比Supremum记录小。
Supremum记录的next_record值为0,该记录之后就没有下一条记录,其是页中单向链表的最后一个节点。

页目录/Page Directory #

为了快速查找数据页中的记录,不必遍历整个链表,InnoDB引入了页目录:

  • 将所有的正常的记录(包括最小记录和最大记录)划分为几个组。
  • 每个组的最后一条记录相当于 “带头大哥”,其记录的头信息中的n_owned属性表示该组内共有几条记录。
  • 将每个组中最后一条记录在页面中的地址偏移量提取出来,按照顺序存储到靠近页面尾部的地方。这个地方就是Page Directory。页目录中的这些地址偏移量成为槽(Slot)。

InnoDB对于每个分组中的记录条数是有规定的:对于Infimum记录所在的分组中只能有1条记录,Supremum记录所在的分组拥有的记录条数只能在18条之间,剩下的分组中记录的条数范围只能是在48条之间。

每次插入的时候,从页目录中找到键值比待插入记录的键值大且差值最小的槽(即第一个比待插入记录键值大的槽)。

页面头部/Page Header #

Page Header记录了数据页中的记录的状态信息,比如存储了多少条记录、Free Space在页面中的地址偏移量、页目录中存储了多少个槽等。其中部分状态/字段为:

  • PAGE_N_DIR_SLOTS 。 在页目录中的槽数量。
  • PAGE_FREE。 各个已删除的记录通过next_record组成一个单向链表。PAGE_FREE表示改链表头节点对应记录在页面中的偏移量。
  • PAGE_GARBAGE。已删除记录占用的字节数。
  • PAGE_LEVEL。当前页在B+树中所处的层级。
  • PAGE_MAX_TRX_ID。修改当前页的最大事务id,该值仅在二级索引页面中定义。
  • PAGE_INDEX_ID。索引id,表示当前页属于哪个索引。

File Header #

File Header是各种类型的页通用部分,描述一些通用部分,是各种类型的页第一个组成部分。其内容组成如下:

  • FIL_PAGE_SPACE_OR_CHECKSUM 页的校验和。
  • FILE_PAGE_OFFSET 页号。
  • FILE_PAGE_PREV 上一个页的页号。
  • FILE_PAGE_NEXT 下一个页的页号。
  • FILE_PAGE_LSN 页面被最后修改的LSN值。
  • FILE_PAGE_TYPE 页的类型。
  • FILE_PAGE_ARCH_LOG_NO_OR_SPACE_ID 页所属的表空间。

File Trailer #

File Trailer的作用主要是检测一个页是否完整,可以分成2部分:

  • 前4字节代表页的校验和。如果页面刷新成功,则页首和页尾的校验和应该是一致的。 二者不同则意味着刷新期间发生了错误。
  • 后4字节代表页面被最后修改时对应的LSN的后4字节。