行格式,也就是在页中,每行的记录如何存储。
innodb中,行格式主要有4种。但是整体上,大同小异。

  1. 记录的额外信息这部分,是服务器为了描述这条记录而不得不额外添加的一些信息,这些额外信息分为3类,分别是变长字段长度列表NULL值列表记录头信息
  2. 记录真实的数据。

todo💡

当然没怎么介绍记录头信息,后续有空填坑。

为什么要这么麻烦,有4种格式呢?本质上,还是为了尽可能减少行记录占的大小,这样每页就可以存储更多的数据。
这里处理的麻烦点,在于变长字段和NULL值处理。

行格式字段长度处理长度存储1个字节还是2个字节NULL值处理溢出页处理
REDUNDANT用的少了,早期使用字段偏移长度偏移列表(重点,存储全部字段的偏移数据)判断整个记录真实数据的占用大小,<=127就使用1个字节。粒度大,是整行记录都用1个字节或者2个字节,而不是根据某些列来偏移数据的最高位,标识是否为NULL,所以真实占用字节用1个字节还是2个字节,是判断<=127,因为最高位给了NULL值表示真实数据前768字节 +20字节溢出页地址
COMPACT变长字段列表,会重复利用表定义,这里只存储变长的字段长度列表结合表定义来决定,表定义最大1个字节,则直接用1个字节。否则真实数据<=127,则用1个字节,因为最高位用来判断,是1个字节还是2个字节。bitmap处理。将可能为NULL值的列表,通过Bitmap表示真实数据前768字节 +20字节溢出页地址
DYNAMIC 默认行格式COMPACT一样COMPACT一样只存储20字节的溢出页地址
COMPRESSED 压缩版COMPACT一样COMPACT一样只存储20字节的溢出页地址,并且主要是会对页边进行压缩

COMPACT行格式

变长字段列表 + NULL值列表 + 记录头信息。

技巧💡

针对变长字段,在额外信息中记录真实数据的占用字节数大小,来达到记录变长字节,而不是直接按最大字节来分配。
针对NULl值列表,我们可以通过bitmap来记录,当前值是否为NULL值。很明显,我们只需要记录可能为NULL的字段来生成NULL的bitmap即可。那哪些字段是可以为NULL值的?怎么判断?当时是在表结构定义的时候就已经知道了。

变长字段列表

image.png
mysql列数和行大小限制

NULL值处理(bitmap)

空值的处理,就比较简单。直接找出可能为空的列表,通过bitmap来存储。标识每个字符是否是空值。

  1. 主键列、被NOT NULL修饰的列都是不可以存储NULL值的,所以在统计的时候不会把这些列算进去。比方说表test3个列c1、c3、c4都是允许存储NULL值的,而c2列是被NOT NULL修饰,不允许存储NULL值。
  2. 如果表中没有允许存储 NULL 的列,则 NULL值列表也不存在了,否则将每个允许存储NULL的列对应一个二进制位,二进制位按照列的顺序逆序排列。二进制位的值为1时,代表该列的值为NULL,为0时,代表该列的值不为NULL。高位补0
    image.png

REDUNDANT格式(已废弃)

了解了,COMPACT格式,REDUNDANT就很好理解了。首先,它也区分记录额外的信息和真实的数据2部分。
额外信息:

  • 字段长度偏移列表
  • 真实数据
    REDUNDANT比,很容易发现,他没有NULL值的bitmap.那他是如何处理NULL值的呢?

字段长度偏移列表

  • 这里是字段长度,注意这里不像REDUNDANT,不是变长。意味着它会记录该条记录(包含隐藏列)的长度信息。所以才是他有点浪费。
  • 记录的是偏移量,而不是具体的长度数据,不够直观。(怎么理解?)
    • 第一列,长度是 20. 第二列,偏移量是30.那么第二列的长度是(30-20=10)。

NULL值处理。 高位表示

这里,没有使用COMPACT的方式,使用bitmap来表示,而是将偏移量的最高位,来作为是否为NULL值。

怎么判断是1个字节还是2个字节

(通过记录实际占用的字节数来判断,如果>127,则全部字节都使用2个字节来表示长度。在header中会有个标识,来记录是1个字节还是2个字节表示长度)
为什么是>127,就是2个字节?因为最高位给判断是否NULL的标识了

溢出页处理方式

保留真实数据的前768字节 + 20字节溢出页面地址

[DYNAMIC]

COMPACT基本一样,但是对溢出页处理方式不一样。它记录的是20字节溢出页面地址,没有保留真实数据的前768个字节数据。

[COMPRESSED]
DYNAMIC没什么不同,主要在于进行了数据压缩。

文章

varchar有最大长度吗 - 知乎

MySQL的varchar水真的太深了——InnoDB记录存储结构_varchar存储结构_砖业洋__的博客-CSDN博客

MySQL :: MySQL 8.0 Reference Manual :: 8.4.7 Limits on Table Column Count and Row Size