空列值是否与填充列值占用相同的存储空间?

Har*_*man 19 mysql optimization

我有一个有 2 列的表格。两列的类型都设置为varchar(38)。如果我为其中一列创建一个值为空的行,它是否会占用与该值不为空相同的存储空间?

换句话说,当创建一行时,MySQL 是否会为该列保留存储空间(取决于其类型)?

Rol*_*DBA 17

来自Innodb 物理行结构,REDUNDANT ROW_FORMAT 下的第 7 号要点

SQL NULL 值在记录目录中保留一或两个字节。除此之外,如果存储在可变长度列中,SQL NULL 值会在记录的数据部分保留零字节。在定长列中,它在记录的数据部分保留该列的定长。为 NULL 值保留固定空间可以将列从 NULL 更新为非 NULL 值,从而在不导致索引页碎片的情况下完成。

来自Innodb 物理行结构,COMPACT ROW_FORMAT 下的第 2 项要点

记录头的可变长度部分包含一个位向量,用于指示 NULL 列。如果索引中可以为 NULL 的列数为 N,则位向量占用 CEILING(N/8) bytes。(例如,如果有 9 到 15 列可以为 NULL,则位向量使用两个字节。)为 NULL 的列不占用此向量中的位以外的空间。标题的可变长度部分还包含可变长度列的长度。每个长度需要一个或两个字节,具体取决于列的最大长度。如果索引中的所有列都不是 NULL 并且具有固定长度,则记录头没有可变长度部分。

基于这些要点,这里是一个NULL值占用列的存储

  • 可变长度:NULL 值不占用行本身的存储空间
  • 定长:占用预留空间

现在,您必须在使用 CHAR 和 VARCHAR 之间做出决定,因为第一点提出了什么

为 NULL 值保留固定空间使列从 NULL 更新为非 NULL 值可以就地完成,而不会导致索引页碎片化

这将防止在存储非 NULL 数据后引入任何行的碎片。这是我之前讨论过的关于 MyISAM 的内容:请参阅我的旧帖子在固定大小的字段上使用 CHAR 与 VARCHAR 对性能有何影响?.


Cra*_*ein 10

无论您为 varchar 列定义的长度如何,空列使用的存储空间都是相同的。

CHAR 和 VARCHAR 类型

在此处输入图片说明

这仅解决 varchar 列使用的空间,不考虑行、其索引、主键和其他列使用的总存储空间。

正如 ypercube 在他的评论中提到的,当存在至少一个可为空的列时,对于整个行存储还有其他注意事项。

Innodb 物理行结构

记录头的可变长度部分包含一个位向量,用于指示 NULL 列。如果有 9 到 15 列可以为 NULL,则位向量使用两个字节。)

...

标题的可变长度部分还包含可变长度列的长度。每个长度需要一个或两个字节,具体取决于列的最大长度。如果索引中的所有列都不是 NULL 并且具有固定长度,则记录头没有可变长度部分

是的,使用的存储空间根据您选择的类型而变化,是固定的还是可变的,整理和其他因素,例如引擎。

MySQL 在此处提出优化数据存储的建议:优化数据大小

更新

varchar 的另一个考虑因素,那就是内存。在 MySQL 中尽可能地限制可变长度列的大小很重要。即使列是可变的并且使用的存储空间是可变的,MySQL 也会以固定块的形式分配内存来存储值。例如 varchar(200) 将使用比 varchar(5) 更多的内存。这不是存储空间问题,但在定义列时仍然需要考虑。

  • 上面的数字假设“字符集”latin1 或 ascii。对于 utf8,“CHAR(4)”所需的存储空间为 12。 (2认同)