MySQL:The CHAR and VARCHAR Types

时间:2022-07-24
本文章向大家介绍MySQL:The CHAR and VARCHAR Types,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

CHAR 和 VARCHAR 类型相似,但在存储的检索时有区别,同时在最大长度定义与尾部空格上是否保留也有区别。

CHAR 和 VARCHAR 声明时格式为 CHAR(num) 和 VARCHAR(num),这里的 num 表示的是你想存储的最大字符数。注意是字符数,而不是字节数。

一、长度定义区别

CHAR(num),存储时长度是固定的,num值的范围在[0, 255](0和255均可取值)。当存储的字符不足时,会右边补足空格。

VARCHAR(num),长度定义为变长,num值的范围是[0, 65535]。需要注意的是这里的 65535 是所有列的总和不能超过的值,也就是说当只有一个 VARCHAR 列时可选的最大值。

即 VARCHAR 仅使用必要空间,一般情况下,它比 CHAR 要更节省空间。

二、存储区别

VARCHAR 会额外使用1到2个字节来记录字符串的长度。当长度小于等于255字节时,使用1个字节,大于255字节时使用2个字节。

此外,VARCHAR 在更新时需要做额外的操作,因为如果更新的操作是将行变得更长,并且在页内没有更多的空间可以存储,在这种情况下,不同的存储引擎的处理方式不一样。例如 MyISAM 会将行拆成不同的片段存储,InnoDB则需要分裂页来使行可以放进页内。总而言之都会带开额外的操作。而 CHAR 因为每次分配的空间都是固定的,因为不会有这个问题存在。

所以,当长度比较小或者长度固定时,更适合用 CHAR 类型来存储,因为不会经常变动,且节省了空间。

三、尾部空格截断区别

CHAR 类型不足长度时会在右侧补足空格,但在检索时会自动移除掉右边的空格(这里的移除不仅是自动补足的,实际插入的也会移除)。但当 sql_mode 设置为 PAD_CHAR_TO_FULL_LENGTH 时,则不会被移除。示例如下(mysql版本5.7,后同):

CREATE TABLE t1 (c1 CHAR(10));

INSERT INTO t1 (c1) VALUES('xy');

set sql_mode = '';

show variables like 'sql_mode';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sql_mode      |       |
+---------------+-------+

SELECT concat('(', c1, ')'), CHAR_LENGTH(c1) FROM t1;
+----------------------+-----------------+
| concat('(', c1, ')') | CHAR_LENGTH(c1) |
+----------------------+-----------------+
| (xy)                 |               2 |
+----------------------+-----------------+

SET sql_mode = 'PAD_CHAR_TO_FULL_LENGTH';

mysql> SELECT concat('(', c1, ')'), CHAR_LENGTH(c1) FROM t1;
+----------------------+-----------------+
| concat('(', c1, ')') | CHAR_LENGTH(c1) |
+----------------------+-----------------+
| (xy        )         |              10 |
+----------------------+-----------------+

VARCHAR 不会填充空格,而对于实际插入的尾部空格,在4.1版本之前,VHARCHAR的处理方式和 CHAR 是一致的,但是之后的版本中,VARCHAR则会保留空格。示例如下:

CREATE TABLE vc (v VARCHAR(4), c CHAR(4));

INSERT INTO vc VALUES ('ab  ', 'ab  ');

SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab  )              | (ab)                |
+---------------------+---------------------+

四、总结

  • 对于数据如何存储,取决于存储引擎,并非所有的存储引擎都会按照相同的方式处理定长和变长的字符串,比如 Memory 引擎只支持定长的行,即使有变长的行也会根据最大长度分配空间
  • 但对于填充和截断空格行为在不同存储引擎上都是一样的,因为这是在 MySQL 服务器层进行处理的
  • 在实际进行表创建时,要根据实际情况进行选择。一般对于长度固定,或者长度特别小时,适合用 CHAR ,比如存储密码的 md5 值的情况就很适合用 CHAR

五、扩展

使用 VARCHAR(5) 和 VARCHAR(10) 存储 hello 的空间开销是一样的,那实际使用更短的列有什么优势吗?

更长的列会消耗更多的内存。因为 MySQL 通常会分配固定大小的内存块来保存内部值,尤其是使用内存临时表进行排序或操作时。在利用磁盘临时表进行排序也同样糟糕。所以,最好的策略是只分配真正需要的空间。from 《高性能MySQL》

六、参考资料

  1. 官方文档
  2. 《高性能MySQL》第四章