InnoDB行格式
InnoDB 存储引擎设计了4种不同类型的行格式,分别是
- Compact
- Redundant
- Dynamic
- Compressed
指定行格式的语法
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称;
ALTER TABLE 表名 ROW_FORMAT=行格式名称;
Compact格式
变长字段长度列表
在 Compact 行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长 字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放
变长字段长度列表中只存储值不为 NULL 的列内容占用的长度,值为 NULL 的列的长度 是不储存的 。
varchar的最大长度
变长字段的长度最大不可以超过 2 字节,这是因在 MySQL 数据库中 VARCHAR 类型的最大长度限制为 65535。变长字段之后的第二个部分是 NULL 标志位,该位指示了该行数据中是否有 NULL 值,有则用 1 表示。该部分所占的字节应该为 1 字节。接下来的部分是记录头信息(record header),固定占用 5 字节(40 位),每位的含义见表:
对于 blob,text,varchar(8099 这样的大字段,innodb 只会存放前 768 字节在数据页中,而剩余的数据则会存储在溢出段中(发生溢出情况的时候适用),对于行溢出数据,其存放采用下图中所示方法;
innoDB 存储引擎表是索引组织的,即 B+Tree 的结构,这样每个页中至少应该有两条行记录(否则失去了B+Tree的意义,变成链表了)。因此,如果页中只能存放下一条记录,那么 InnoDB 存储引擎会自动将行数据存放到溢出页中,所以默认页 16KB,那么一行数据列和如果超过 8kB 则会出现之前溢出的错误。
null值列表
- 首先统计表中允许存储 NULL 的列有哪些
- 如果表中没有允许存储 NULL 的列,则 NULL 也不存在了,否则将每个允许存储 NULL 的列对应一个
二进制位,二进制位按照列的顺序逆序排列:- 二进制位的值为 1 时,代表该列的值为 NULL 。
- 二进制位的值为 0 时,代表该列的值不为 NULL 。
如果一行null的列大于8,会继续加一个字节存储null值
记录头信息
除了 变长字段长度列表 、 NULL值列表 之外,还有一个用于描述记录的 记录头信息 ,它是由固定的 5 个字节组 成。 5 个字节也就是 40 个二进制位,不同的位代表不同的意思,如图:
记录的真实数据
对于 record_format_demo 表来说, 记录的真实数据 除了 c1 、 c2 、 c3 、 c4 这几个我们自己定义的列的数据 以外, MySQL 会为每个记录默认的添加一些列(也称为 隐藏列 ),具体的列如下:
InnoDB 表对主键的生成策略
- 优先使用用户自定义主键作为主键
- 如果用户没有定义主键,则 选取一个 Unique 键作为主键
- 如果表中连 Unique 键都没有定义的话,则 InnoDB 会为表默认添加一个名为row_id 的隐藏列作为主键。
所以我们从上表中可以看出:
InnoDB存储引擎会为每条记录都添加 transaction_id 和 roll_pointer 这两个列,但是 row_id 是可选的(在没有自定义主键以及Unique键的情况下才会添加该列)。
Dynamic和Compressed行格式
Dynamic 和 Compressed 行格式,我现在使用的 MySQL 版本是 5.7 ,它的默认行格 式就是 Dynamic ,这俩行格式和 Compact 行格式挺像,只不过在处理 行溢出 数据时有点儿分歧,它们不会在记 录的真实数据处存储字段真实数据的前 768 个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数 据处存储其他页面的地址,就像这样:
Compressed 行格式和 Dynamic 不同的一点是, Compressed 行格式会采用压缩算法对页面进行压缩,以节省空间。