在 MySQL 中,null 究竟对性能和存储(空间)有什么影响?
例如:
TINYINT:1 字节 TINYINT w/NULL 1 字节 + 以某种方式存储 NULL?
这取决于您使用的存储引擎。
在 MyISAM 格式中,每个行标题包含一个位域,每列一个位用于编码 NULL 状态。为 NULL 的列仍会占用空间,因此 NULL 不会减少存储空间。见https://dev.mysql.com/doc/internals/en/myisam-introduction.html
在 InnoDB 中,每一列在行头中都有一个“字段起始偏移量”,即每列一个或两个字节。如果该列为 NULL,则该字段开始偏移中的高位打开。在这种情况下,根本不需要存储该列。因此,如果您有很多 NULL,您的存储空间应该会大大减少。见https://dev.mysql.com/doc/internals/en/innodb-field-contents.html
编辑:
NULL 位是行标题的一部分,您不要选择添加它们。
我可以想象 NULL 提高性能的唯一方法是,在 InnoDB 中,如果行包含 NULL,则一页数据可能适合更多行。所以你的 InnoDB 缓冲区可能更有效。
但是,如果这在实践中提供了显着的性能优势,我会感到非常惊讶。担心 NULL 对性能的影响属于微优化领域。你应该把注意力集中在其他地方,在那些能带来更大收益的领域。例如添加精心挑选的索引或增加数据库缓存分配。
比尔的回答很好,但有点过时了。使用一或两个字节存储 NULL 仅适用于InnoDB REDUNDANT 行格式。由于 MySQL 5.0.3 InnoDB 使用COMPACT行格式,它只使用一位来存储 NULL(当然,一个字节是最小值),因此:
NULL 所需的空间 = CEILING(N/8) 字节,其中 N 是一行中的 NULL 列数。
根据有关 COMPACT vs REDUNDANT 的 MySQL 官方网站:
紧凑行格式将行存储空间减少了大约 20%,但代价是增加了某些操作的 CPU 使用率。如果您的工作负载是典型的受缓存命中率和磁盘速度限制的工作负载,那么紧凑格式可能会更快。
您开始看到这里的节省:
另一方面,我建议在空字符串或零上使用 NULL,因为它们更有条理、更便携,并且需要更少的空间。为了提高性能和节省空间,请专注于使用正确的数据类型、索引和查询,而不是使用奇怪的技巧。
更多信息: https ://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html
我同意 Bill Karwin 的观点,尽管我会添加这些 MySQL 技巧。11 号特别解决了这个问题:
首先,问问自己,空字符串值与 NULL 值之间是否有任何区别(对于 INT 字段:0 与 NULL)。如果没有理由同时拥有两者,则不需要 NULL 字段。(你知道 Oracle 认为 NULL 和空字符串是一样的吗?)
NULL 列需要额外的空间,它们会增加比较语句的复杂性。尽可能避免它们。但是,我知道有些人可能有非常具体的理由来使用 NULL 值,这并不总是一件坏事。
另一方面,我仍然在没有大量行的表上使用 null,主要是因为我喜欢说 NOT NULL 的逻辑。
更新 稍后再谈,我要补充一点,我个人不喜欢在数据库中使用 0 而不是 NULL,我也不推荐它。如果您不小心,这很容易在您的应用程序中导致大量误报。
dev.mysql.com/doc/refman/5.0/en/is-null-optimization.html
MySQL 可以对 col_name IS NULL 执行与 col_name = constant_value 相同的优化。例如,MySQL 可以使用索引和范围来搜索 NULL 与 IS NULL