磁盘上表数据的存储要求取决于几个因素。不同的存储引擎对数据类型进行表示和存储原始数据的方式不同。表数据可能会被压缩,无论是针对某个列还是针对整行,这使得计算表或列的存储要求变得复杂。
尽管磁盘上的存储布局存在差异,但用于在所有存储引擎之间传递和交换有关表行信息的内部 MySQL API 使用一致的数据结构。
本节包括 MySQL 支持的每种数据类型的存储要求的指南和信息,包括使用固定大小表示数据类型的存储引擎的内部格式和大小。信息按类别或存储引擎列出。
表内部表示的最大行大小为 65,535 字节,即使存储引擎能够支持更大的行。此数字不包括 BLOB
或 TEXT
列,它们对该大小的贡献仅为 9 到 12 字节。对于 BLOB
和 TEXT
数据,信息存储在与行缓冲区不同的内存区域中。不同的存储引擎根据它们用于处理相应类型的方法以不同的方式处理此数据的分配和存储。有关更多信息,请参阅 第 18 章,备选存储引擎 和 第 10.4.7 节,“表列数和行大小的限制”。
NDB
表使用 4 字节对齐;所有 NDB
数据存储都以 4 字节的倍数进行。因此,通常需要 15 字节的列值在 NDB
表中需要 16 字节。例如,在 NDB
表中,TINYINT
、SMALLINT
、MEDIUMINT
和 INTEGER
(INT
) 列类型由于对齐因素,每条记录需要 4 字节存储空间。
每个 BIT(
列占用 M
)M
位的存储空间。虽然单个 BIT
列 不是 4 字节对齐,但 NDB
为每行保留 4 字节(32 位)用于 BIT
列所需的第一个 1-32 位,然后为位 33-64 再保留 4 字节,依此类推。
虽然 NULL
本身不需要任何存储空间,但如果表定义包含任何允许 NULL
的列,NDB
将为每行保留 4 字节,最多 32 个 NULL
列。(如果 NDB Cluster 表定义了超过 32 个 NULL
列,最多 64 个 NULL
列,则将为每行保留 8 字节。)
每个使用 NDB
存储引擎的表都需要一个主键;如果您没有定义主键,NDB
将创建一个 “隐藏” 主键。此隐藏主键会消耗每个表记录 31-35 字节。
您可以使用 ndb_size.pl Perl 脚本估算 NDB
存储要求。它连接到当前的 MySQL(不是 NDB Cluster)数据库,并生成关于该数据库如果使用 NDB
存储引擎将需要多少空间的报告。有关更多信息,请参阅 第 25.5.29 节,“ndb_size.pl - NDBCLUSTER 大小要求估算器”。
数据类型 | 所需存储空间 |
---|---|
TINYINT |
1 字节 |
SMALLINT |
2 字节 |
MEDIUMINT |
3 字节 |
INT 、INTEGER |
4 字节 |
BIGINT |
8 字节 |
FLOAT( |
如果 0 <= p <= 24,则为 4 字节;如果 25 <= p <= 53,则为 8 字节 |
FLOAT |
4 字节 |
DOUBLE [PRECISION] 、REAL |
8 字节 |
DECIMAL( 、NUMERIC( |
可变;请参阅以下讨论 |
BIT( |
大约 (M +7)/8 字节 |
DECIMAL
(以及 NUMERIC
)列的值使用二进制格式表示,该格式将九个十进制(以 10 为基数)数字打包到四个字节中。每个值的整数和小数部分的存储空间是分别确定的。九个数字的每个倍数需要四个字节,而 “剩余” 数字需要四个字节的一部分。剩余数字所需的存储空间由下表给出。
剩余数字 | 字节数 |
---|---|
0 | 0 |
1 | 1 |
2 | 1 |
3 | 2 |
4 | 2 |
5 | 3 |
6 | 3 |
7 | 4 |
8 | 4 |
对于在 MySQL 5.6.4 之前创建的表,TIME
、DATETIME
和 TIMESTAMP
列所需的存储空间与从 5.6.4 开始创建的表不同。这是因为 5.6.4 中的一项更改允许这些类型具有小数部分,这需要 0 到 3 个字节。
数据类型 | MySQL 5.6.4 之前的存储要求 | 从 MySQL 5.6.4 开始的存储要求 |
---|---|---|
YEAR |
1 字节 | 1 字节 |
DATE |
3 字节 | 3 字节 |
TIME |
3 字节 | 3 个字节 + 小数秒存储 |
DATETIME |
8 字节 | 5 个字节 + 小数秒存储 |
TIMESTAMP |
4 字节 | 4 个字节 + 小数秒存储 |
从 MySQL 5.6.4 开始,YEAR
和 DATE
的存储空间保持不变。但是,TIME
、DATETIME
和 TIMESTAMP
的表示方式不同。DATETIME
的打包效率更高,非小数部分需要 5 个字节而不是 8 个字节,所有三个部分都有一个需要 0 到 3 个字节的小数部分,具体取决于存储值的毫秒精度。
毫秒精度 | 所需存储空间 |
---|---|
0 | 0 个字节 |
1, 2 | 1 字节 |
3, 4 | 2 字节 |
5, 6 | 3 字节 |
例如,TIME(0)
、TIME(2)
、TIME(4)
和 TIME(6)
分别使用 3、4、5 和 6 个字节。 TIME
和 TIME(0)
等效,并且需要相同的存储空间。
有关时间值的内部表示的详细信息,请参阅 MySQL 内部机制:重要算法和结构。
在下表中,M
表示非二进制字符串类型的声明列长度(以字符为单位)和二进制字符串类型的字节数。 L
表示给定字符串值的实际字节长度。
数据类型 | 所需存储空间 |
---|---|
CHAR( |
InnoDB 行格式的紧凑系列优化了可变长度字符集的存储。请参阅 COMPACT 行格式存储特征。否则,M × w 个字节,<= 255,其中 w 是字符集中最大长度字符所需的字节数。 |
BINARY( |
M 个字节,0 <= 255 |
VARCHAR( , VARBINARY( |
如果列值需要 0 − 255 个字节,则为 L + 1 个字节;如果值可能需要超过 255 个字节,则为 L + 2 个字节 |
TINYBLOB , TINYTEXT |
L + 1 个字节,其中 L < 28 |
BLOB , TEXT |
L + 2 个字节,其中 L < 216 |
MEDIUMBLOB , MEDIUMTEXT |
L + 3 个字节,其中 L < 224 |
LONGBLOB , LONGTEXT |
L + 4 个字节,其中 L < 232 |
ENUM(' |
1 或 2 个字节,具体取决于枚举值的个数(最多 65,535 个值) |
SET(' |
1、2、3、4 或 8 个字节,具体取决于集合成员的个数(最多 64 个成员) |
可变长度字符串类型使用长度前缀加数据进行存储。长度前缀需要 1 到 4 个字节,具体取决于数据类型,前缀的值为 L
(字符串的字节长度)。例如,MEDIUMTEXT
值的存储需要 L
个字节来存储值,加上 3 个字节来存储值的长度。
要计算存储特定 CHAR
、VARCHAR
或 TEXT
列值所使用的字节数,您必须考虑该列使用的字符集以及值是否包含多字节字符。特别是,在使用 UTF-8 Unicode 字符集时,您必须记住并非所有字符都使用相同的字节数。 utf8mb3
和 utf8mb4
字符集最多可以分别使用每个字符 3 个和 4 个字节。有关用于不同类别 utf8mb3
或 utf8mb4
字符的存储空间细分的说明,请参阅 第 12.9 节,“Unicode 支持”。
VARCHAR
、VARBINARY
以及 BLOB
和 TEXT
类型是可变长度类型。对于每个类型,存储要求取决于以下因素
列值的实际长度
列的最大可能长度
用于该列的字符集,因为某些字符集包含多字节字符
例如,VARCHAR(255)
列可以保存最大长度为 255 个字符的字符串。假设该列使用 latin1
字符集(每个字符一个字节),则实际所需的存储空间是字符串的长度 (L
),加上一个字节来记录字符串的长度。对于字符串 'abcd'
,L
为 4,存储要求为 5 个字节。如果同一列改为声明为使用 ucs2
双字节字符集,则存储要求为 10 个字节:'abcd'
的长度为 8 个字节,并且该列需要 2 个字节来存储长度,因为最大长度大于 255(最多 510 个字节)。
可以在 VARCHAR
或 VARBINARY
列中存储的 字节 的有效最大数量受 65,535 字节的最大行大小限制,该大小在所有列之间共享。对于存储多字节字符的 VARCHAR
列,字符 的有效最大数量更少。例如,utf8mb4
字符最多可以使用每个字符 4 个字节,因此使用 utf8mb4
字符集的 VARCHAR
列最多可以声明为 16,383 个字符。请参阅 第 10.4.7 节,“表列数和行大小的限制”。
InnoDB
将长度大于或等于 768 个字节的固定长度字段编码为可变长度字段,可以存储在页面外。例如,CHAR(255)
列如果字符集的最大字节长度大于 3,则可能会超过 768 个字节,例如 utf8mb4
。
NDB
存储引擎支持可变宽度列。这意味着 NDB Cluster 表中的 VARCHAR
列需要与其他任何存储引擎相同的存储空间,除了这些值是 4 字节对齐的。因此,使用 latin1
字符集存储在 VARCHAR(50)
列中的字符串 'abcd'
需要 8 个字节(而不是在 MyISAM
表中使用相同列值的 5 个字节)。
TEXT
、BLOB
和 JSON
列在 NDB
存储引擎中的实现方式不同,其中该列中的每一行都由两个独立的部分组成。其中一个部分大小固定(TEXT
和 BLOB
为 256 字节,JSON
为 4000 字节),实际上存储在原始表中。另一个部分包含超过 256 字节的所有数据,存储在隐藏的 blob 部件表中。此第二个表中的行大小由列的精确类型决定,如下表所示
类型 | Blob 部件大小 |
---|---|
BLOB , TEXT |
2000 |
MEDIUMBLOB , MEDIUMTEXT |
4000 |
LONGBLOB , LONGTEXT |
13948 |
JSON |
8100 |
这意味着 TEXT
列的大小如果 size
<= 256(其中 size
表示行的大小)则为 256;否则,大小为 256 + size
+ (2000 × (size
− 256) % 2000)。
NDB
不会为 TINYBLOB
或 TINYTEXT
列值单独存储 blob 部件。
您可以使用在创建或修改父表时在列注释中使用的 NDB_COLUMN
将 NDB
blob 列的 blob 部件大小增加到最大值 13948。NDB
还支持使用在列注释中使用的 NDB_TABLE
设置 TEXT
、BLOB
或 JSON
列的内联大小。有关更多信息,请参阅 NDB_COLUMN 选项。
ENUM
对象的大小由不同的枚举值的数量决定。对于最多 255 个可能值的枚举,使用 1 个字节。对于具有 256 到 65,535 个可能值的枚举,使用 2 个字节。请参阅 第 13.3.5 节,“ENUM 类型”。
一个 SET
对象的大小由不同集合成员的数量决定。如果集合大小为 N
,则该对象占用 (
字节,向上取整到 1、2、3、4 或 8 字节。一个 N
+7)/8SET
最多可以有 64 个成员。请参见 第 13.3.6 节,“SET 类型”。
MySQL 使用 4 个字节来存储几何值,用于指示 SRID,后面跟着值的 WKB 表示。 LENGTH()
函数返回值存储所需的字节数。
有关 WKB 和空间值内部存储格式的描述,请参见 第 13.4.3 节,“支持的空间数据格式”。
通常, JSON
列的存储需求与 LONGBLOB
或 LONGTEXT
列的存储需求大致相同;也就是说,JSON 文档所占用的空间与将该文档的字符串表示存储在这些类型之一的列中所占用的空间大致相同。但是,二进制编码会带来一些开销,包括存储在 JSON 文档中的各个值的查找所需的元数据和字典。例如,存储在 JSON 文档中的字符串需要 4 到 10 字节的额外存储空间,具体取决于字符串的长度以及存储它的对象或数组的大小。
此外,MySQL 对存储在 JSON
列中的任何 JSON 文档的大小施加了一个限制,使其不能大于 max_allowed_packet
的值。