MySQL/InnoDB 如何在内部表示 NULL 值?
How does MySQL/InnoDB represent NULL values internally?
在 MySQL 中(或者我应该说:使用 MySQL 的 InnoDB 引擎)- 空值是如何表示的?即,如果允许列具有 NULL
s,table(或单个记录,如果它在记录级别)的表示如何变化?
如果不同的列数据类型不同 - 要么解释表示 NULL 的各种方法,要么只选择一种数据类型(例如 INT
)。
参考
https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html
引用和解释
ROW_FORMAT=REDUNDANT
:
An SQL NULL value reserves one or two bytes in the record directory. Besides that, an SQL NULL value reserves zero bytes in the data part of the record if stored in a variable length column. In a fixed-length column, it reserves the fixed length of the column in the data part of the record. Reserving the fixed space for NULL values enables an update of the column from NULL to a non-NULL value to be done in place without causing fragmentation of the index page.
即 1 bit/col 为 NULL,不节省数据。
ROW_FORMAT=COMPACT
:
The variable-length part of the record header contains a bit vector for indicating NULL columns. If the number of columns in the index that can be NULL is N, the bit vector occupies CEILING(N/8) bytes. (For example, if there are anywhere from 9 to 15 columns that can be NULL, the bit vector uses two bytes.) Columns that are NULL do not occupy space other than the bit in this vector. The variable-length part of the header also contains the lengths of variable-length columns. Each length takes one or two bytes, depending on the maximum length of the column. If all columns in the index are NOT NULL and have a fixed length, the record header has no variable-length part.
也就是1个bit/col,0个space的数据。
我怀疑,没有证据,DYNAMIC
和 COMPRESSED
就像 COMPACT
。
列长度
每一列前面都有一个 1 或 2 字节的长度。 1 或 2 的选择基于最大潜在列宽。 (注意:虽然 LONGTEXT
需要 4 个字节的长度,但 'length' 实际上是在谈论存储在记录中的数量,而不是溢出。)
溢出存储
虽然我在讨论这个话题,但这里有一些关于 "long" strings/blobs 发生的事情的信息——无论是在记录中,还是存储在其他地方:
- <= 40 bytes (in a given column): 存储在记录中。
- 如果整条记录在 8KB 左右:存储在记录中。
- 否则,
COMPACT
:长列为 768+20
- 否则,
DYNAMIC
和 COMPRESSED
:长列为 20
"768"表示text/blob的前768个字节存入记录; “20”表示存储其余(或全部)的 20 字节 'pointer'。
KEY_BLOCK_SIZE
控制多少列数据存储在聚簇索引中,多少放在溢出页上。
(我将 REDUNDANT
排除在外,因为我没有详细信息。)
经验法则
每个 InnoDB 行有 20-30 字节的开销。
一个 BTree(包括 InnoDB 的数据,加上每个二级索引)随着块分裂等而被吸引到 69%
"Data_free" 严重不完整;不要相信它。
MyISAM 在 space 上非常简朴;为 MyISAM table 计算 space 很容易。从那里乘以 2-3 得到 InnoDB 所需的 space。 (也有例外,经常涉及到MyISAM分片、PK聚类等问题)
这仅适用于 COMPACT(REDUNDANT 仅出于历史原因才有意义,除非您访问字典 tables)。
对于每个 NULL-able 列,NULLS header.
中有一位
如果 table NULL 中没有 NULL-able 字段 header 大小为零。
如果列值为 NULL,则该位被设置并且记录数据中没有值。
如果列值不为 NULL,则取消设置该位,并且列值存储在记录的数据中。
在 MySQL 中(或者我应该说:使用 MySQL 的 InnoDB 引擎)- 空值是如何表示的?即,如果允许列具有 NULL
s,table(或单个记录,如果它在记录级别)的表示如何变化?
如果不同的列数据类型不同 - 要么解释表示 NULL 的各种方法,要么只选择一种数据类型(例如 INT
)。
参考
https://dev.mysql.com/doc/refman/5.7/en/innodb-physical-record.html
引用和解释
ROW_FORMAT=REDUNDANT
:
An SQL NULL value reserves one or two bytes in the record directory. Besides that, an SQL NULL value reserves zero bytes in the data part of the record if stored in a variable length column. In a fixed-length column, it reserves the fixed length of the column in the data part of the record. Reserving the fixed space for NULL values enables an update of the column from NULL to a non-NULL value to be done in place without causing fragmentation of the index page.
即 1 bit/col 为 NULL,不节省数据。
ROW_FORMAT=COMPACT
:
The variable-length part of the record header contains a bit vector for indicating NULL columns. If the number of columns in the index that can be NULL is N, the bit vector occupies CEILING(N/8) bytes. (For example, if there are anywhere from 9 to 15 columns that can be NULL, the bit vector uses two bytes.) Columns that are NULL do not occupy space other than the bit in this vector. The variable-length part of the header also contains the lengths of variable-length columns. Each length takes one or two bytes, depending on the maximum length of the column. If all columns in the index are NOT NULL and have a fixed length, the record header has no variable-length part.
也就是1个bit/col,0个space的数据。
我怀疑,没有证据,DYNAMIC
和 COMPRESSED
就像 COMPACT
。
列长度
每一列前面都有一个 1 或 2 字节的长度。 1 或 2 的选择基于最大潜在列宽。 (注意:虽然 LONGTEXT
需要 4 个字节的长度,但 'length' 实际上是在谈论存储在记录中的数量,而不是溢出。)
溢出存储
虽然我在讨论这个话题,但这里有一些关于 "long" strings/blobs 发生的事情的信息——无论是在记录中,还是存储在其他地方:
- <= 40 bytes (in a given column): 存储在记录中。
- 如果整条记录在 8KB 左右:存储在记录中。
- 否则,
COMPACT
:长列为 768+20 - 否则,
DYNAMIC
和COMPRESSED
:长列为 20
"768"表示text/blob的前768个字节存入记录; “20”表示存储其余(或全部)的 20 字节 'pointer'。
KEY_BLOCK_SIZE
控制多少列数据存储在聚簇索引中,多少放在溢出页上。
(我将 REDUNDANT
排除在外,因为我没有详细信息。)
经验法则
每个 InnoDB 行有 20-30 字节的开销。
一个 BTree(包括 InnoDB 的数据,加上每个二级索引)随着块分裂等而被吸引到 69%
"Data_free" 严重不完整;不要相信它。
MyISAM 在 space 上非常简朴;为 MyISAM table 计算 space 很容易。从那里乘以 2-3 得到 InnoDB 所需的 space。 (也有例外,经常涉及到MyISAM分片、PK聚类等问题)
这仅适用于 COMPACT(REDUNDANT 仅出于历史原因才有意义,除非您访问字典 tables)。 对于每个 NULL-able 列,NULLS header.
中有一位如果 table NULL 中没有 NULL-able 字段 header 大小为零。
如果列值为 NULL,则该位被设置并且记录数据中没有值。
如果列值不为 NULL,则取消设置该位,并且列值存储在记录的数据中。