13.7 数据类型存储要求
在磁盘上存储表数据的要求取决于多个因素。不同的存储引擎对数据类型和存储原始数据的方式不同。表数据可能会被压缩,单个列或整个行都可能会被压缩,这使得计算表或列的存储要求变得复杂。
尽管磁盘上的存储布局不同,MySQL 的内部 API,用于通信和交换关于表行的信息,使用一致的数据结构,适用于所有存储引擎。
本节包括 MySQL 支持的每种数据类型的存储要求信息,包括存储引擎使用固定大小表示数据类型的内部格式和大小。信息按类别或存储引擎分类。
表的内部表示最大行大小为 65,535 字节,即使存储引擎可以支持更大的行。这个数字不包括 BLOB 或 TEXT 列,这些列只占用 9 到 12 字节。对于 BLOB 和 TEXT 数据,信息存储在内存中的不同区域中。不同的存储引擎根据它们的方法来分配和存储这些数据。更多信息,请见 第 18 章,《Alternative Storage Engines》 和 第 10.4.7 节,“Limits on Table Column Count and Row Size”。
NDB 表使用4字节对齐;所有NDB数据存储都是以4字节为单位的。因此,在NDB表中,一个通常需要15字节的列值需要16字节。例如,在NDB表中,TINYINT、SMALLINT、MEDIUMINT和INTEGER(INT)列类型每个记录都需要4字节存储空间,因为是对齐因子。
每个BIT列需要M位存储空间。虽然单个BIT列不是4字节对齐的,但NDB为每个行保留4字节(32位)用于第1-32位的BIT列,然后是4字节用于33-64位,依此类推。
虽然NDB本身不需要存储NULL本身,但是NDB为每个行保留4字节,如果表定义中包含任何允许NULL的列,直到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 Size Requirement Estimator”以获取更多信息。
| Data Type | Storage Required |
|---|---|
TINYINT |
1 字节 |
SMALLINT |
2 字节 |
MEDIUMINT |
3 字节 |
INT, INTEGER |
4 字节 |
BIGINT |
8 字节 |
FLOAT( |
4 字节,如果 0 <= p <= 24,8 字节,如果 25 <= p <= 53 |
FLOAT |
4 字节 |
DOUBLE [PRECISION], REAL |
8 字节 |
DECIMAL(, NUMERIC( |
变长;请查看以下讨论 |
BIT( |
大约 (M+7)/8 字节 |
DECIMAL (DECIMAL 和 NUMERIC) 列使用的存储格式是将十进制(base 10)9个数字打包到4个字节中。整数和小数部分的存储是独立的。每9个数字需要4个字节,剩余的数字需要部分4个字节。超出数字的存储要求见下表。
| Leftover Digits | Number of Bytes |
|---|---|
| 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个字节。
| Data Type | Storage Required Before MySQL 5.6.4 | Storage Required as of MySQL 5.6.4 |
|---|---|---|
YEAR |
1 byte | 1 byte |
DATE |
3 bytes | 3 bytes |
TIME |
3 bytes | 3 bytes + fractional seconds storage |
DATETIME |
8 bytes | 5 bytes + fractional seconds storage |
TIMESTAMP |
4 bytes | 4 bytes + fractional seconds storage |
从 MySQL 5.6.4 开始,对YEAR和DATE的存储要求保持不变。然而,TIME、DATETIME和TIMESTAMP的表示方式不同。DATETIME被打包得更紧凑,需要5个字节,而不是8个字节的非小数部分,所有三个部分都有小数部分,需要0到3个字节,取决于存储值的小数秒精度。
| Fractional Seconds Precision | Storage Required |
|---|---|
| 0 | 0 bytes |
| 1, 2 | 1 byte |
| 3, 4 | 2 bytes |
| 5, 6 | 3 bytes |
例如,TIME(0)、TIME(2)、TIME(4)和TIME(6)使用3、4、5和6个字节,分别。TIME和TIME(0)等效,需要相同的存储空间。
关于时间值的内部表示,详见MySQL Internals: Important Algorithms and Structures。
在以下表格中,M 表示非二进制字符串类型的列长度(字符)或二进制字符串类型的列长度(字节)。L 表示给定字符串值的实际长度(字节)。
| Data Type | Storage Required |
|---|---|
CHAR( |
InnoDB 行格式的紧凑家族优化存储变长字符集。详见COMPACT Row Format Storage Characteristics。否则,M × w 字节,<= 255,where w 是最大长度字符在字符集中的字节数。 |
BINARY( |
M 字节,0 <= 255 |
VARCHAR(, VARBINARY( |
L + 1 字节,如果列值需要0-255字节,L + 2 字节,如果值可能需要超过255字节 |
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 个字节 per 字符。有关不同类别 utf8mb3 或 utf8mb4 字符的存储使用情况的详细信息,请参阅 第 12.9 节,“Unicode 支持”。
VARCHAR, VARBINARY 和 BLOB 和 TEXT 类型是可变长度类型。对于每种类型,存储要求取决于以下因素:
列值的实际长度
列的最大可能长度
用于该列的字符集,因为一些字符集包含多字节字符
要计算存储特定 CHAR、VARCHAR 或 TEXT 列值使用的字节数,您必须考虑该列使用的字符集以及该值是否包含多字节字符。特别是,当使用 UTF-8 Unicode 字符集时,您必须记住并非所有字符都使用相同数量的字节。utf8mb3 和 utf8mb4 字符集每个字符最多可以分别需要三个和四个字节。有关 utf8mb3 或 utf8mb4 字符不同类别所用存储的细分,请参阅 第 12.9 节“Unicode 支持”。
VARCHAR、VARBINARY 以及 BLOB 和 TEXT 类型是可变长度类型。对于每种类型,存储需求取决于以下因素:
-
列值的实际长度
-
列的最大可能长度
-
用于该列的字符集,因为某些字符集包含多字节字符
例如,一个VARCHAR(255)列可以存储最长255个字符的字符串。假设该列使用latin1字符集(每个字符一个字节),实际存储需求是字符串的长度(L),加上记录字符串长度的1个字节。对于字符串'abcd',L为4,存储需求为5个字节。如果同一个列使用ucs2双字节字符集,存储需求为10个字节:'abcd'的长度为8个字节,列需要2个字节存储长度,因为最大长度大于255(最多510个字节)。
字节的实际最大数量可以存储在VARCHAR或VARBINARY列中,受65,535个字节的最大行大小限制,这个限制是所有列共享的。对于存储多字节字符的VARCHAR列,实际最大数量的字符是少的。例如,utf8mb4字符可以需要每个字符4个字节,因此一个VARCHAR列使用utf8mb4字符集可以被声明为最多16,383个字符。请参见第10.4.7节,“表列计数和行大小限制”。
InnoDB将长度大于或等于768字节的固定长度字段编码为可变长度字段,可以存储在off-page中。例如,一个CHAR(255)列可以超过768字节,如果最大字节长度的字符集大于3,如utf8mb4。
NDB存储引擎支持可变宽度列。这意味着一个VARCHAR列在NDB集群表中需要相同的存储量,除了该值是4字节对齐。因此,字符串'abcd'在VARCHAR(50)列中使用latin1字符集需要8个字节(而不是5个字节的同一个列值在MyISAM表中)。
TEXT, BLOB, 和JSON 列在NDB存储引擎中实现 differently,wherein每个行在列中由两个独立部分组成。其中一个是固定的大小(256字节为TEXT和BLOB,4000字节为JSON),实际存储在原始表中。另一个是超过256字节的数据,存储在隐藏的blob parts表中。该表中的行大小由列的确切类型确定,如下表所示:
| Type | Blob Part Size |
|---|---|
BLOB, TEXT |
2000 |
MEDIUMBLOB, MEDIUMTEXT |
4000 |
LONGBLOB, LONGTEXT |
13948 |
JSON |
8100 |
这意味着TEXT 列的大小为256,如果size <= 256(其中size 表示行的大小),否则大小为256 + size + (2000 × (size − 256) % 2000)。
NDB不对TINYBLOB或TINYTEXT 列的blob parts单独存储。
您可以使用NDB在创建或更改父表时,通过在列注释中使用NDB_COLUMN将blob列的blob部分大小增加到13948。NDB还支持为TEXT、BLOB或JSON 列设置内联大小,使用NDB_COLUMN。见NDB_COLUMN Options,了解更多信息。
一个ENUM对象的大小由枚举值的数量确定。一个字节用于枚举值少于255的枚举。两个字节用于枚举值在256和65535之间的枚举。见Section 13.3.5, “The ENUM Type”。
SET 对象的大小由不同的成员个数确定。如果集合大小为 N,对象占用 ( 字节,向上舍入到 1、2、3、4 或 8 字节。SET 可以有最多 64 个成员。请参阅第13.3.6节,“SET 类型”。N+7)/8
MySQL 使用 4 字节来表示 SRID,后跟着 WKB 值的表示。LENGTH() 函数返回值存储所需的字节空间。
关于 WKB 和内部存储格式的描述,请参阅第13.4.3节,“支持的空间数据格式”。
一般来说,JSON 列的存储需求与 LONGBLOB 或 LONGTEXT 列的存储需求相似,即 JSON 文档的空间需求与文档的字符串表示形式在这些类型的列中的空间需求相似。然而,JSON 文档的二进制编码需要的元数据和字典,以便在对象或数组中查找值。例如,字符串存储在 JSON 文档中需要 4 到 10 字节的额外存储空间,取决于字符串的长度和对象或数组的大小。
此外,MySQL 对 JSON 文档在 JSON 列中的大小施加限制,使其不能超过max_allowed_packet 的值。