第 2.1 节:CHAR(n)
CHAR(n) 是一个固定长度为 n 个字符的字符串。如果它的字符集是 utf8mb4,则无论其中包含什么文本,它都会精确占用 4 * n 字节。
大多数使用 CHAR(n) 的场景涉及包含英文字符的字符串,因此应使用 ascii 字符集(latin1 也可以)。
country_code CHAR(2) CHARACTER SET ascii,
postal_code CHAR(6) CHARACTER SET ascii,
uuid CHAR(39) CHARACTER SET ascii, -- 更多讨论见其他章节
第 2.2 节:DATE, DATETIME, TIMESTAMP, YEAR, TIME
DATE数据类型包含日期但不包含时间部分。其格式为'YYYY-MM-DD',取值范围为'1000-01-01'到'9999-12-31'。DATETIME类型包含时间,格式为'YYYY-MM-DD HH:MM:SS',取值范围为'1000-01-01 00:00:00'到'9999-12-31 23:59:59'。TIMESTAMP类型是一个整数类型,包含日期和时间,有效范围从'1970-01-01 00:00:01' UTC到'2038-01-19 03:14:07' UTC。YEAR类型表示年份,取值范围为 1901 到 2155。TIME类型表示时间,格式为'HH:MM:SS',取值范围为'-838:59:59'到'838:59:59'。
存储需求
| 数据类型 | 在 MySQL 5.6.4 之前 | 从 MySQL 5.6.4 开始 |
|---|---|---|
| YEAR | 1 字节 | 1 字节 |
| DATE | 3 字节 | 3 字节 |
| TIME | 3 字节 | 3 字节 + 小数秒存储 |
| DATETIME | 8 字节 | 5 字节 + 小数秒存储 |
| TIMESTAMP | 4 字节 | 4 字节 + 小数秒存储 |
小数秒(从 5.6.4 版本开始)
| 小数秒精度 | 存储所需字节数 |
|---|---|
| 0 | 0 字节 |
| 1, 2 | 1 字节 |
| 3, 4 | 2 字节 |
| 5, 6 | 3 字节 |
请参阅 MySQL 手册:DATE、DATETIME 和 TIMESTAMP 类型,数据类型存储需求,以及时间值中的小数秒。
第 2.3 节:VARCHAR(255) — 是否使用 255
建议的最大长度
首先,我提到一些常见的字符串,它们总是十六进制或以其他方式限于 ASCII。对于这些,你应该指定 CHARACTER SET ascii(latin1 也可以)以避免浪费空间:
UUID CHAR(36) CHARACTER SET ascii -- 或压缩为 BINARY(16)
country_code CHAR(2) CHARACTER SET ascii
ip_address CHAR(39) CHARACTER SET ascii -- 或压缩为 BINARY(16)
phone VARCHAR(20) CHARACTER SET ascii -- 可能足够处理分机号
postal_code VARCHAR(20) CHARACTER SET ascii -- (不是 'zip_code')(不知道最大长度)
city VARCHAR(100) -- 这个俄罗斯城镇需要 91 个字符:Poselok Uchebnogo Khoyaystva Srednego Professionalno-Tekhnicheskoye Uchilishche Nomer Odin
country VARCHAR(50) -- 可能足够
name VARCHAR(64) -- 可能足够;比某些政府机构允许的还要长
为什么不用 255?有两个原因反对在所有地方都使用 (255) 的常见做法。
- 当一个复杂的
SELECT需要创建临时表(用于子查询、UNION、GROUP BY等)时,首选使用MEMORY引擎,它将数据放在 RAM 中。但VARCHAR在此过程中会转换为CHAR。这使得VARCHAR(255) CHARACTER SET utf8mb4占用 1020 字节。这可能导致需要溢出到磁盘,从而变慢。 - 在某些情况下,InnoDB 会查看表中列的可能大小,并决定表太大,从而中止
CREATE TABLE。
VARCHAR 与 TEXT
关于 *TEXT、CHAR 和 VARCHAR 的使用提示,以及一些最佳实践:
- 永远不要使用
TINYTEXT。 - 几乎永远不要使用
CHAR——它是固定长度的;每个字符占用字符集的最大长度(例如,utf8mb4每个字符 4 字节)。使用CHAR时,除非你知道需要其他字符集,否则应使用CHARACTER SET ascii。 VARCHAR(n)会在n个字符处截断;而TEXT会在某个字节数处截断。(但是,你真的想要截断吗?)*TEXT可能会因为临时表的处理方式而拖慢复杂的SELECT查询。
第 2.4 节:INT 作为 AUTO_INCREMENT
任何大小的 INT 都可以用于 AUTO_INCREMENT。UNSIGNED 始终是合适的。
请注意,某些操作会“消耗”AUTO_INCREMENT 的 ID。这可能导致意外的间隙。例如:INSERT IGNORE 和 REPLACE。它们可能会在意识到不需要该 ID 之前预先分配一个 ID。这是 InnoDB 引擎的预期行为,也是设计使然,不应因此阻止使用它们。
第 2.5 节:其他类型
已经有单独的条目介绍“FLOAT、DOUBLE 和 DECIMAL”以及“ENUM”。关于数据类型的单独页面可能会显得冗长——我建议“字段类型”(或者应该叫“数据类型”?)作为一个概述,然后拆分为以下主题页面:
- 整数类型
- FLOAT、DOUBLE 和 DECIMAL
- 字符串(CHAR、TEXT 等)
- BINARY 和 BLOB
- DATETIME、TIMESTAMP 及相关类型
- ENUM 和 SET
- 空间数据
- JSON 类型(MySQL 5.7.8+)
- 如何表示货币,以及其他需要“改造”到现有数据类型中的常见“类型”
在适当的情况下,每个主题页面除了语法和示例外,还应包括:
ALTER时的注意事项- 大小(字节)
- 与非 MySQL 引擎的对比(低优先级)
- 在
PRIMARY KEY或二级索引中使用该数据类型的注意事项 - 其他最佳实践
- 其他性能问题
第 2.6 节:隐式/自动类型转换
SELECT '123' * 2;
为了与 2 相乘,MySQL 自动将字符串 '123' 转换为数字。
返回值:
246
数字转换从左到右进行。如果无法转换,结果为 0。
SELECT '123ABC' * 2;
返回值:
246
SELECT 'ABC123' * 2;
返回值:
0
第 2.7 节:数值类型介绍
MySQL 提供了多种不同的数值类型。它们可以分为以下几组:
| 分组 | 类型 |
|---|---|
| 整数类型 | INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT |
| 定点数类型 | DECIMAL, NUMERIC |
| 浮点数类型 | FLOAT, DOUBLE |
| 位值类型 | BIT |
第 2.8 节:整数类型
最小的无符号值始终为 0。
| 类型 | 存储(字节) | 有符号最小值 | 有符号最大值 | 无符号最大值 |
|---|---|---|---|---|
| TINYINT | 1 | -128 | 127 | 255 |
| SMALLINT | 2 | -32,768 | 32,767 | 65,535 |
| MEDIUMINT | 3 | -8,388,608 | 8,388,607 | 16,777,215 |
| INT | 4 | -2,147,483,648 | 2,147,483,647 | 4,294,967,295 |
| BIGINT | 8 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 | 18,446,744,073,709,551,615 |
第 2.9 节:定点数类型
MySQL 的 DECIMAL 和 NUMERIC 类型用于存储精确的数值数据。建议使用这些类型来保持精确精度,例如用于货币。
DECIMAL
这些值以二进制格式存储。在列声明中,应指定精度(precision)和小数位数(scale)。
- 精度表示值为存储的有效数字位数。
- 小数位数表示小数点后存储的数字位数。
salary DECIMAL(5,2)
5 表示精度,2 表示小数位数。对于此示例,可以存储在此列中的值的范围是 -999.99 到 999.99。
如果省略小数位数参数,则默认为 0。
此数据类型最多可以存储 65 位数字。
DECIMAL(M,N) 占用的字节数大约为 M/2。
第 2.10 节:浮点数类型
FLOAT 和 DOUBLE 表示近似数据类型。
| 类型 | 存储 | 精度 | 范围 |
|---|---|---|---|
| FLOAT | 4 字节 | 23 个有效位 / 约 7 位十进制数字 | 10^±38 |
| DOUBLE | 8 字节 | 53 个有效位 / 约 16 位十进制数字 | 10^±308 |
REAL是FLOAT的同义词。DOUBLE PRECISION是DOUBLE的同义词。
尽管 MySQL 也允许使用 (M,D) 限定符,但请不要使用它。(M,D) 表示值最多可以存储 M 位总位数,其中 D 位在小数点后。数字将被四舍五入两次或被截断;这将带来更多麻烦而非好处。
由于浮点值是近似的,而不是精确存储的值,尝试在比较中将其视为精确值可能会导致问题。特别要注意,FLOAT 值很少等于 DOUBLE 值。
第 2.11 节:位值类型
BIT 类型对于存储位字段值很有用。BIT(M) 允许存储最多 M 位的值,其中 M 的取值范围是 1 到 64。
你也可以使用位值表示法指定值。
b'111' -- 7
b'10000000' -- 128
有时使用“移位”来构造单个位的值很方便,例如 (1 << 7) 对应 128。
NDB 表中所有 BIT 列的最大总大小为 4096 字节。