The physical structure of records in InnoDB(8.行记录的物理结构)

《学习InnoDB:核心之旅》中,我介绍了innodb_diagrams项目来记录InnoDB的内部,它提供了这篇文章中用到的图表。稍后,在对innodb_ruby的快速介绍中,我介绍了innodb_space命令行工具的安装和一些快速演示。
在InnoDB索引页的物理结构中描述了InnoDB索引页的物理结构,在InnoDB的B+树索引结构中描述了InnoDB的逻辑结构。现在我们将详细了解这些页面中使用的记录的物理结构。
在这篇文章中,只考虑了紧凑行格式(用于Barracuda表格式)。

record的偏移量

在前面的文章中,record的offset已经在许多需要指向记录的结构中被描述过,record的offset指向记录数据本身开始,他的长度是可变的,但是每个记录前面都有一个记录头,它的长度也是可变的。在这篇文章和相关的插图中,我们用N表示记录的开始,其中记录数据为N,使用正的offset例如N+1,而记录头使用的负offset如N-1。InnoDB通常从记录的起始位置,位置N为原点。

record的标题

在以前的文章中,record的标题被提到过几次,但是没有被完全描述,如上所述,记录头先于记录本身,其结构如下:
The physical structure of records in InnoDB(8.行记录的物理结构)

记录头中的一些字段如下:

  • Next Record Offset: 按Key升序排列的从当前记录到页中的下一个记录远点的相对offset。
  • Record Type:记录的类型,目前只支持4个值,0表示常规,1表示节点指针,2表示infimum,3表示supremum。
  • Order:此记录插入堆中的顺序,堆记录包括infimum和supremum从0开始编号。极限值总是序号为0,最高的序号为1,插入的用户记录将从2开始编号。
  • Number of Records Owned:页牡蛎中当前记录拥有的记录数,这个领域将在以后关于页面目录的文章中进一步讨论。
  • Info Flags:用于存储此记录的布尔标识的4位位图。目前只定义了两个标识,min_rec(1)表示该记录是B+树的非叶子级的最小记录。deleted(2)表示该记录被删除并且在将来被一个清除操作实际删除。
  • Nullable field bitmap (optional):每个可控字段的1个位,用于存储字段是否为空,四舍五入到整个字节数。如果一个字段为空,那么它的字段值将从记录的Key或者行部分中删除。如果没有字段可控,则该位图将不存在。
  • Variable field lengths array (optional):每个可变长度字段的8位或者16位的整数数组,取决于字段的最大大小,如果没有可变长度的字段,则此数组不存在。

记录标题每行至少5个字节,但是对于具有许多可变宽度字段的记录,它可能会大得多。

聚簇索引

聚簇索引有一个更复杂的记录结构:
The physical structure of records in InnoDB(8.行记录的物理结构)

字段如下:

  • Cluster Key Fields: 聚簇索引字段链接在一起,InnoDB只是将每个列类型的内部存储格式的原始字节连接到一个单独的字节流中。
  • Transaction ID: 48位的整型表示最后修改的记录。
  • Roll Pointer:一种结构,包含最近修改该记录的事务的撤销记录的回顾段中的位置信息,回滚指针结构的字段是,1位的 is insert标识,7位的回滚段ID,4字节的页号和undo log位置。2字节的offset。
  • Non-Key Fields:所有的非主键字段连接在一起,成为一个字节流。

非叶子页记录的结构类似,但是稍微简单一些:
The physical structure of records in InnoDB(8.行记录的物理结构)

由于非叶子页不是MVCC,事务ID和回滚指针字段被移除。其中不包含非主键字段,而是包含此节点指针锁指向的子页号。由于聚簇索引不能为空,因此不存在可空字段的位图。

辅助索引

InnoDB的辅助索引与聚簇索引的总体结构相同,但是他们不包含非主键的字段。而是包含聚簇索引字段,也成为主键值或者常见的PKV。如果在辅助索引和聚簇索引之间有任何字段重叠,那么重叠字段将从存储在辅助索引记录中的聚集Key中删除。例如,如果一个表有一个主键(a,b,c)和辅助的索引(c,d),那么索引中辅助的key将如预期那样,(a,d),但是pkv只包含(b,c)。
由于辅助键包含非唯一且可为空的字段,因此如果需要,可以同时提供可变字段长度的数组和科委空的字段位图。否则,叶子的页面结构就会非常简单:
The physical structure of records in InnoDB(8.行记录的物理结构)

与聚簇索引一样,辅助键的字段被连接到单个字节流中,聚簇索引键的字段以完全的形式连接在一起形成PKV。
辅助索引的非叶子页面看起来页非常熟悉:
The physical structure of records in InnoDB(8.行记录的物理结构)

对于辅助索引非叶子页中有一点需要注意,聚簇索引的key字段PKV包含在记录中,被认为是记录Key的一部分。而不是他的值。辅助索引可能不是唯一的,但是页面中的每条记录都必须有唯一的标识。因此必须在记录中包含PKV以确保唯一性。这意味着从属的非叶子页中的记录将比对应的叶子页大4个字节。

对每行记录开销的一个说明

看看上面的例子,你可以很容易的计算处InnoDB所需要的每行开销。聚簇索引的关键叶子页头部至少需要5个字节。事务ID需要6个字节,回滚指针需要7个字节。每行总共需要18个字节,对于非常窄的表,这种开销可能相当高。
此外,每个页面都有很大的开销,而低效地填充页面会浪费大量的空间,例如页面可能只填充了一半。

下一章预告

在下一篇文章中,我将描述页面目录及其在高效的检索中的用途。
我需要更正一下,可控字段的位图不会出现在聚簇索引的叶子页上,但是实际上,如果任何非主键字段可空,它就会出现。在非叶子的集群key页上,它总是不存在的。引文集群的key必须为not null 。