InnoDB记录存储结构

InnoDB 行格式

InnoDB设计了4种不同的行格式, 分别是Compact、Redundant、Dynamic和Compressed.

指定行格式的语法

CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称

ALTER TABLE 表名 ROW_FORMAT=行格式名称

Compact

在Compact格式的行中,一条完整的记录可以被分为记录的额外信息记录的真实数据两大部分.

记录的额外信息

InnoDB为了描述一条数据的信息,需要在数据开头添加额外的一些信息,这些信息分为三类,分别是: 变长字段长度列表NULL值列表记录头信息

  1. 变长字段长度列表: Mysql支持一些边长数据类型,例如: VARCHAR, TEXT, BOLB, VARBINARY. 我们把拥有这些数据类型的列为变长字段, 变长字段中存储的字节数是不固定的. Compact行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放.
    ** 如果表使用的字符集是不变长字符集,例如: ASCII(每个字符一个字节),那么拥有CHAR类型的列不是变长字段,如果字符集是变长字符集, 例如: UTF8(每个字符1-3个字节, UTF8-MB4 1-4个字节) 那么拥有CHAR类型的列是变长字段 **
  2. NULL值列表: Mysql允许列存储NULL值,所以Compact行格式把这些值为NULL的列统一管理起来,存储到NULL值列表中. 它的处理过程:
    1. 首先统计表中允许存储NULL值的列
      1. 将每个允许存储NULL值的列对应一个二级制位,二进制位按照列的顺序逆序排列. 二进制位的值为1时,代表该列的值为NULL, 二进制位的值为0时,代表该列的值不为NULL.
      2. NULL值列表必须用整数个字节的位表示,如果使用的二进制位个数不是整数个字节, 则在字节的高位补0.
      ** 如果表中没有允许存储 NULL 的列,则 NULL值列表 也不存在了**
  3. 记录头信息
    1. delete_mask: 1个字节,表示行是否被删除,值为0表示没有删除,被删除的记录依然保存在上,因为删除和重新排列数据会影响性能,删除的记录会组成一个垃圾链表, 垃圾链表中记录的存储空间为可重用空间,当有新的插入时可能把这些被删除的记录占用的存储空间覆盖掉.

Redundant

Mysql5 之前使用的行格式

Dynamic 和 Compressed

Mysql5.7后默认使用Dynamic作为默认的行格式
Dynamic 和 Compressed 处理行数据的方式与Compact基本相似,只不过在处理行溢出数据时有分歧. 另外Compressed行格式会采用压缩算法对页面进行压缩,以节省空间。

行溢出

InnoDB将磁盘中的数据分成16KB的页,也就是16384字节,并规定一个页中最少存在两条数据. 每个页除了存放我们的记录以外,也需要存储一些额外的信息, 这些信息加在一起需要132个字节. 每行数据记录额外信息的数据为27个字节, 所以一行数据的最大长度:

132 + 2 × (27 + n) < 16384

得出的解为: n < 8099. 而一个VARCHAR类型的列就最多可以存储65532个字节,显然8099字节不能满足需求.
对于CompactRedundant行格式来说,如果某一列中的数据非常多的话,在本记录的真实数据处只会存储该列的前768个字节的数据和一个指向其他页的地址(20个字节),然后把剩下的数据存放到其他页中,这个过程也叫做行溢出,存储超出768字节的那些页面也被称为溢出页。而DynamicCompressed在处理行溢出时: 不会在记录的真实数据处存储字段真实数据的前768个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地址.