MySQL/InnoDB 如何在内部表示 NULL 值?

ein*_*ica 2 mysql innodb

在 MySQL 中(或者我应该说:使用 MySQL 的 InnoDB 引擎)-如何表示空值?即如果允许列具有NULLs ,表(或单个记录,如果它在记录级别)的表示如何更改?

如果不同的列数据类型不同 - 要么解释表示 NULL 的各种方法,要么只选择一种数据类型(例如INT)。

Ric*_*mes 5

参考

https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html

报价和解释

ROW_FORMAT=REDUNDANT

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

也就是说,NULL 为 1 位/列,不节省数据。

ROW_FORMAT=COMPACT

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

也就是说,1 位/列,数据的零空间。

我怀疑,在没有证据的情况下,那DYNAMICCOMPRESSED就像COMPACT

柱长

每列前面都有 1 或 2 字节的长度。1 或 2 的选择基于最大潜在列宽。(注意:虽然LONGTEXT需要 4 字节的长度,但“长度”实际上是指存储在记录中的数量,而不是溢出的数量。)

溢出存储

当我谈到这个话题时,这里有一些关于“长”字符串/blob 会发生什么的信息——无论是在记录中,还是存储在其他地方:

  • <= 40 字节(在给定的列中):存储在记录中。
  • 如果整个记录大约有 8KB:存储在记录中。
  • 否则,和COMPACT: 768+20 对于长列
  • 否则,andDYNAMICCOMPRESSED: 20 表示长列

“768”表示文本/blob的前768个字节存储在记录中;“20”表示一个 20 字节的“指针”,指向其余(或全部)的存储位置。

KEY_BLOCK_SIZE 控制在聚集索引中存储多少列数据,以及在溢出页上放置多少列数据。

(我REDUNDANT不说了,因为我没有详细信息。)

经验法则

每个 InnoDB 行有 20-30 字节的开销。

BTree(包括 InnoDB 的数据,加上每个二级索引)随着块的拆分等被吸引到 69%。

“Data_free”非常不完整;不要相信它。

MyISAM 在空间上非常简洁;计算 MyISAM 表的空间很容易。从那里乘以 2-3 以获得 InnoDB 所需的空间。(也有例外,常涉及MyISAM分片、PK聚类等)