磁盘上表数据的存储需求取决于几个因素。不同的存储引擎以不同的方式表示数据类型和存储原始数据。表数据可以被压缩,可以是针对列,也可以是针对整行,这使得计算表或列的存储需求变得复杂。
尽管磁盘上的存储布局不同,但用于通信和交换表行信息的内部 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
为 BIT
列所需的前 1-32 位每行保留 4 个字节(32 位),然后为 33-64 位再保留 4 个字节,依此类推。
虽然 NULL
本身不需要任何存储空间,但如果表定义包含任何允许 NULL
的列,则 NDB
每行保留 4 个字节,最多 32 个 NULL
列。(如果 NDB 集群表定义了超过 32 个 NULL
列到 64 个 NULL
列,则每行保留 8 个字节。)
每个使用 NDB
存储引擎的表都需要一个主键;如果您没有定义主键,则 NDB
会创建一个“隐藏”主键。此隐藏主键每个表记录消耗 31-35 个字节。
您可以使用 ndb_size.pl Perl 脚本来估算 NDB
存储需求。它连接到当前的 MySQL(不是 NDB 集群)数据库,并创建一个报告,说明如果使用 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 |
对于 TIME
、DATETIME
和 TIMESTAMP
列,在 MySQL 5.6.4 之前创建的表的存储需求与 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
字符集(每个字符 1 个字节),则实际所需的存储空间为字符串的长度(L
)加上 1 个字节来记录字符串的长度。对于字符串 '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 个字节的固定长度字段编码为可变长度字段,这些字段可以存储在页外。例如,如果字符集的最大字节长度大于 3(如 utf8mb4
),则 CHAR(255)
列可能会超过 768 个字节。
NDB
存储引擎支持变宽列。这意味着 NDB Cluster 表中的 VARCHAR
列所需的存储空间与任何其他存储引擎相同,但此类值按 4 字节对齐。因此,使用 latin1
字符集存储在 VARCHAR(50)
列中的字符串 'abcd'
需要 8 个字节(而不是 MyISAM
表中同一列值的 5 个字节)。
在 NDB
存储引擎中,TEXT
、BLOB
和 JSON
列的实现方式不同,其中列中的每一行都由两个独立的部分组成。其中一个是固定大小的(TEXT
和 BLOB
为 256 字节,JSON
为 4000 字节),实际上存储在原始表中。另一个部分包含任何超过 256 字节的数据,这些数据存储在一个隐藏的 blob parts 表中。下表显示了此第二张表中行的大小由列的确切类型决定
类型 | Blob Part 大小 |
---|---|
BLOB 、TEXT |
2000 |
MEDIUMBLOB 、MEDIUMTEXT |
4000 |
LONGBLOB 、LONGTEXT |
13948 |
JSON |
8100 |
这意味着如果 size
<= 256(其中 size
表示行的大小),则 TEXT
列的大小为 256;否则,大小为 256 + size
+ (2000 × (size
− 256) % 2000)。
NDB
不会单独存储 TINYBLOB
或 TINYTEXT
列值的 blob parts。
您可以在创建或修改父表时,使用列注释中的 NDB_COLUMN
将 NDB
blob 列的 blob part 大小增加到最大 13948。 NDB
还支持使用列注释中的 NDB_TABLE
设置 TEXT
、BLOB
或 JSON
列的内联大小。有关更多信息,请参阅 NDB_COLUMN 选项。
ENUM
对象的大小由不同枚举值的个数决定。具有最多 255 个可能值的枚举使用 1 个字节。具有 256 到 65,535 个可能值的枚举使用 2 个字节。请参阅 第 13.3.6 节“ENUM 类型”。
一个 SET
对象的大小由不同的集合成员的数量决定。如果集合大小为 N
,则该对象占用 (
字节,向上取整为 1、2、3、4 或 8 字节。一个 N
+7)/8SET
最多可以有 64 个成员。请参阅 第 13.3.7 节,“SET 类型”。
MySQL 使用 4 个字节来存储几何值,其中包含指示 SRID 的值,后跟值的 WKB 表示形式。LENGTH()
函数返回存储值所需的字节空间。
有关 WKB 和空间值的内部存储格式的说明,请参阅 第 13.4.3 节,“支持的空间数据格式”。
通常,JSON
列的存储需求与 LONGBLOB
或 LONGTEXT
列大致相同;也就是说,JSON 文档占用的空间与其字符串表示形式存储在其中一种类型的列中所占用的空间大致相同。但是,二进制编码会产生一定的开销,包括存储在 JSON 文档中的各个值的元数据和查找所需的字典。例如,存储在 JSON 文档中的字符串需要额外存储 4 到 10 个字节,具体取决于字符串的长度以及存储字符串的对象或数组的大小。
此外,MySQL 对存储在 JSON
列中的任何 JSON 文档的大小施加了限制,使其不能大于 max_allowed_packet
的值。