MySQL InnoDB行格式

本文将介绍 MySQL 中 InnoDB 存储引擎的行格式。

一、概述

1. 什么是 InnoDB行格式?

在 MySQL 中,数据以记录的形式存储,这些记录在磁盘上的存放方式也被称为行格式。

在 InnoDB 中,有四种不同类型的行格式,分别为:

  • Compact
  • Redundant
  • Dynamic
  • Compressed

2. 指定行格式

可以在创建、修改表时指定行格式:

1
2
3
CREATE TABLE 表名 ROW_FORMAT=行格式

ALTER TABLE 表名 ROW_FORMAT=行格式

二、Compact 行格式

1. 记录的额外信息 - 变长字段长度列表

MySQL 支持一些变长类型,值的类型为变长类型的列被称为变长字段。

由于变长字段存储时所占用的字节数并不固定,因此需要在存储数据的同时额外存储其占用的字节数。

在 Compact 行格式中,所有变长字段的占用字节长度会组合为一个变长字段长度列表,存放在记录的开头位置。

需要注意的是:

变长字段长度列表中仅记录每个非 null 的变长字段的长度

2. 记录的额外信息 - NULL 值列表

Compact 行格式将所有 “允许 NULL 的列” 的 “NULL 与否信息” 统一存储为 NULL 值列表

具体做法为:分配一块内存空间,其中,每个二进制位对应一个 “允许 NULL 的列”,用二进制值表示对应列的值是否为 NULL。

通过这样的方式,在占用极少空间的情况下,存储了各个 “允许 NULL 的列” 的 “NULL 与否信息”。

3. 记录的额外信息 - 记录头信息

记录头信息 描述该记录的存储信息,分别用二进制位表示了以下信息:

名称 大小 描述
预留位1 1 没有使用
预留位2 1 没有使用
delete_mask 1 标记该记录是否被删除
min_rec_mask 1 表示该记录是否为 B+ 树中每层非叶子节点的最小记录
n_owned 4 表示当前分组拥有的记录数
heap_no 13 表示当前记录在记录堆的位置信息
record_type 3 表示当前记录的类型,0 表示普通记录,1 表示 B+ 树非叶子节点记录(目录项记录),2 表示最小记录,3 表示最大记录
next_record 16 表示下一条记录的相对位置
  • delete_mask:标记该记录是否被删除

    之所以不直接删除记录,是因为移除他们以后将其它记录在磁盘上重新排列需要性能消耗,而更改删除标记带来的性能损耗要小得多。

    所有被删除的记录都会组成 “垃圾链表”,链表中记录所占用的空间被称为 “可重用空间”,此后如果有新纪录插入,可能会覆盖这些存储空间。

  • heap_no:表示当前记录在记录堆的位置信息

    值从 2 开始,这是因为 InnoDB 为每个页添加了两个 “伪记录”,它们分别代表 “最大记录”、”最小记录”,正是它们占用了 0 和 1 的编号。

  • next_record:表示下一条记录的相对位置

    表示当前记录到下一条记录的地址偏移量。

    这里的下一条记录,并不是按插入顺序排序,而是按主键值从小到大排序。

    “最小记录” 的下一条记录为本页中主键值最小的记录;本页中主键值最大的记录的下一条记录是 “最大记录”。

    InnoDB 会始终维护一个单链表,其中的各节点按照主键值从小到大顺序连接。

4. 记录的真实数据

记录的帧数数据中会存储所有非 null 的自定义列。

除了自定义的列外,MySQL 会为每个记录默认添加一些 “隐藏列”,如下:

  • DB_ROW_ID:行 ID;唯一标识一条记录;可选,当表没有主键、没有 unique 键时才会添加
  • DB_TRX_ID:事务 ID
  • DB_ROLL_PTR:回滚指针

5. 行溢出

对于存储空间占用较大的列,会这样存储:

  • 用一部分空间存储该列的一部分数据
  • 剩余数据会被分散存储在其它页中,用另一部分空间存储这些数据的指针

三、Redundant行格式

1. 记录的额外信息 - 字段长度偏移列表

将所有列(包括隐藏列)的偏移信息存储到 字段长度偏移列表 中,计算列值长度需要计算差值

2. 记录的额外信息 - 记录头信息

同上。

3. 记录的真实数据

同上。

4. 行溢出

同上。

四、Dynamic 和 Compressed 行格式

Dynamic 和 Compressed 行格式与 Compact 行格式类似,区别在于:行溢出时,Dynamic 和 Compressed 行格式会将所有数据均存储到其它页面,行中只存储指针。

Dynamic 和 Compressed 行格式的不同点是:Compressed 行格式会采用压缩算法对页面进行压缩,以节省空间。

参考

  • MySQL 技术内幕
  • MySQL 实战 45 讲
  • MySQL 是怎样运行的:从根儿上理解 MySQL