【发布时间】:2017-08-27 20:25:57
【问题描述】:
在 MySQL 中(或者我应该说:使用 MySQL 的 InnoDB 引擎)- null 值如何表示?即,如果允许列具有NULLs,则表(或单个记录,如果它在记录级别)的表示如何变化?
如果不同的列数据类型不同 - 请解释表示 NULL 的各种方法,或者只选择一种数据类型(例如INT)。
【问题讨论】:
在 MySQL 中(或者我应该说:使用 MySQL 的 InnoDB 引擎)- null 值如何表示?即,如果允许列具有NULLs,则表(或单个记录,如果它在记录级别)的表示如何变化?
如果不同的列数据类型不同 - 请解释表示 NULL 的各种方法,或者只选择一种数据类型(例如INT)。
【问题讨论】:
参考
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 位/列,数据空间为零。
我怀疑,没有证据,DYNAMIC 和 COMPRESSED 就像 COMPACT。
列长
每列前面都有 1 或 2 字节长度。 1 或 2 的选择基于最大潜在列宽。 (注意:虽然LONGTEXT 需要 4 字节长度,但“长度”实际上是指存储在记录中的数量,而不是溢出。)
溢出存储
当我谈到这个话题时,这里有一些关于“长”字符串/blob会发生什么的信息——无论它是在记录中,还是存储在其他地方:
COMPACT: 768+20 用于长列DYNAMIC 和 COMPRESSED:长列为 20“768”表示text/blob的前768个字节存储在记录中; “20”表示一个 20 字节的“指针”,指向其余部分(或全部)的存储位置。
KEY_BLOCK_SIZE 控制在聚集索引中存储多少列数据,以及在溢出页上放置多少。
(我不知道REDUNDANT,因为我没有详细信息。)
经验法则
每个 InnoDB 行有 20-30 字节的开销。
BTree(包括 InnoDB 的数据,加上每个二级索引)随着块拆分等被吸引到 69%。
“Data_free”非常不完整;不要相信它。
MyISAM 在太空方面非常简陋;计算 MyISAM 表的空间很容易。从那里乘以 2-3 以获得 InnoDB 所需的空间。 (也有例外,常涉及MyISAM分片、PK集群等)
【讨论】:
ROW_FORMAT=COMPRESSED 已在磁盘上压缩,但在缓存中压缩和未压缩 - 使其(在我看来)不值得用于大多数情况。这种压缩(某种程度上)是在块级别,而不是单个列。