11.3.2 CHAR 和 VARCHAR 类型
CHAR
和VARCHAR
类型相似,但是它们的存储和检索方式不同。它们的最大长度以及是否保留尾随空格也不同。
声明CHAR
和VARCHAR
类型的长度,该长度指示您要存储的最大字符数。例如,CHAR(30)
最多可容纳 30 个字符。
CHAR
列的长度固定为创建 table 时声明的长度。长度可以是 0 到 255 之间的任何值。存储CHAR
值时,它们会用空格右填充到指定的长度。检索CHAR
值时,除非启用了PAD_CHAR_TO_FULL_LENGTH SQL 模式,否则删除尾随空格。
VARCHAR
列中的值是可变长度的字符串。长度可以指定为 0 到 65535 之间的值。 VARCHAR
的有效最大长度取决于最大行大小(65535 字节,在所有列之间共享)和所使用的字符集。参见第 8.4.7 节“table 列数和行大小的限制”。
与CHAR
相反,VARCHAR
值存储为 1 字节或 2 字节长的前缀加数据。长度前缀指示值中的字节数。如果值要求不超过 255 个字节,则一列使用一个长度字节;如果值可能需要不超过 255 个字节,则一列使用两个长度字节。
如果未启用严格的 SQL 模式,并且您为CHAR
或VARCHAR
列分配的值超过了该列的最大长度,则该值将被截断以适合并生成警告。对于非空格字符的截断,可以通过使用严格的 SQL 模式导致发生错误(而不是警告)并抑制该值的插入。参见第 5.1.10 节“服务器 SQL 模式”。
对于VARCHAR
列,无论使用哪种 SQL 模式,插入前都会截断超出列长度的尾随空格,并生成警告。对于CHAR
列,无论 SQL 模式如何,都将以静默方式从插入的值中截断多余的尾随空格。
VARCHAR
值在存储时不会填充。根据标准 SQL,在存储和检索值时保留尾随空格。
下 table 通过显示将各种字符串值存储到CHAR(4)
和VARCHAR(4)
列中的结果(假设该列使用诸如latin1
之类的单字节字符集)来说明CHAR
和VARCHAR
之间的区别。
Value | CHAR(4) | Storage Required | VARCHAR(4) | Storage Required |
---|---|---|---|---|
'' | ' ' | 4 bytes | '' | 1 byte |
'ab' | 'ab ' | 4 bytes | 'ab' | 3 bytes |
'abcd' | 'abcd' | 4 bytes | 'abcd' | 5 bytes |
'abcdefgh' | 'abcd' | 4 bytes | 'abcd' | 5 bytes |
table 中最后一行中显示的存储值仅在不使用严格 SQL 模式的情况下适用如果启用了严格模式,那么不会存储超过列长度的值*,并且会导致错误。
InnoDB
将长度大于或等于 768 字节的固定长度字段编码为可变长度字段,可以将其存储在页面外。例如,如果字符集的最大字节长度大于 3,则CHAR(255)
列可以超过 768 个字节,就像utf8mb4
一样。
如果给定值存储在CHAR(4)
和VARCHAR(4)
列中,则从这些列检索的值并不总是相同的,因为在检索时会从CHAR
列中删除尾随空格。以下示例说明了这种差异:
mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO vc VALUES ('ab ', 'ab ');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab ) | (ab) |
+---------------------+---------------------+
1 row in set (0.06 sec)
CHAR
,VARCHAR
和TEXT
列中的值将根据分配给该列的字符集排序规则进行排序和比较。
所有 MySQL 归类均为PAD SPACE
。这意味着将比较所有CHAR
,VARCHAR
和TEXT
值,而不考虑任何尾随空格。在这种情况下,“比较”不包括LIKE模式匹配运算符,对于该运算符,尾随空格很重要。例如:
mysql> CREATE TABLE names (myname CHAR(10));
Query OK, 0 rows affected (0.03 sec)
mysql> INSERT INTO names VALUES ('Jones');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT myname = 'Jones', myname = 'Jones ' FROM names;
+------------------+--------------------+
| myname = 'Jones' | myname = 'Jones ' |
+------------------+--------------------+
| 1 | 1 |
+------------------+--------------------+
1 row in set (0.00 sec)
mysql> SELECT myname LIKE 'Jones', myname LIKE 'Jones ' FROM names;
+---------------------+-----------------------+
| myname LIKE 'Jones' | myname LIKE 'Jones ' |
+---------------------+-----------------------+
| 1 | 0 |
+---------------------+-----------------------+
1 row in set (0.00 sec)
这不受服务器 SQL 模式的影响。
Note
有关 MySQL 字符集和排序规则的更多信息,请参见第 10 章,字符集,排序规则,Unicode。有关存储要求的其他信息,请参见第 11.7 节“数据类型存储要求”。
对于剥离尾随字符或比较忽略它们的情况,如果一列具有要求唯一值的索引,则将仅尾随字符数不同的值插入列中会导致重复键错误。例如,如果 table 包含'a'
,则尝试存储'a '
会导致重复键错误。