MySQL 中 varchar 和 char 有什么区别?
MySQL 中 varchar 和 char 有什么区别?
回答重点
CHAR 和 VARCHAR 是两种用于存储字符串的列类型,它俩最大的不同就是一个是固定长度,一个是可变长度。
- CHAR(n):固定长度的字符串。CHAR 列的长度是固定的,即使存储的字符串长度小于定义的长度,MySQL 也会在字符串的末尾填充空格以达到指定长度(如果 char 类型的字符串后面有空格的话,innodb 会忽略)。
- VARCHAR(n):可变长度的字符串。VARCHAR 列的长度是可变的,存储的字符串长度与实际数据长度相等,并且在存储数据时会额外增加 1 到 2 个字节(字符长度超过 255,则使用两个字节)用于存储字符串的长度信息。
理论上来说 CHAR 会比 VARCHAR 快,因为 VARCHAR 长度不固定,处理需要多一次运算,但是实际上这种运算耗时微乎其微,而固定大小在很多场景下比较浪费空间,除非存储的字符确认是固定大小或者本身就很短,不然业务上推荐使用 VARCHAR。
下面以表格方式总结方便横向对比:
| 特点 | char | varchar |
|---|---|---|
| 存储方式 | 定长字符串(字符串长度小于定义的长度,会使用空格进行填充) | 变长字符串(不会额外填充空格) |
| 存储空间 | 始终占用固定长度空间 | 只占用实际需要的存储空间 |
| 性能影响 | 始终占用固定长度的存储空间,因此在存储时可能会浪费一些空间 (不需要记录额外长度信息,在某些情况下可能更快) |
只占用实际需要的存储空间,因此可以节省存储空间 (需要记录额外长度信息,占据1~2个字节),在某些情况下可能稍微影响性能) |
| 适用场景 | 适合存储固定且短的字符串 | 适合存储变化或较长的字符串 |
扩展知识
MySQL 执行 orderby 排序的时候,会利用 sort_buffer。
假设 a、b、c 都为 varchar 类型,当前要执行select a,b,c from t1 where a = '面试鸭' order by b;
MySQL 计算 a b c 总长度比较长,sort_buffer 可能放不下,就会使用双路排序,即 sort_buffer 里存放需要排序的字段 b 和 id 进行排序,待排完后,再通过 id 回表查询得到a、b、c 字段。这样就多了回表的一步,性能比较差。

如果 select 字段长度少,那么就可以使用单路排序,即将 select 的数据都放入到 sort_buffer 中,排完序后直接返回给客户端。

这里计算 a、b、c 长度依据的就是 varchar(n) 中的 n,所以如果 n 设置很大,虽然占用空间是动态的,但是会隐性影响排序的性能。
更多排序细节可查看面试鸭《MySQL 是如何实现数据的排序的? 》这个面试题。
VARCHAR 支持的最大长度
mysql column length is within the maximum length of 65,535 bytes
因为最大行长度有限,所以要计算 VARCHAR 支持最大长度,仅当一行只有一个 VARCHAR 字段时,这个 VARCHAR 字段能达到最大长度(没有别的字段来占用空间)。
最大行长度是 65535 字节,如果值允许为 null,则需要额外 1bit 标记是否为 null(mysql 最对于 null 值是额外用一个 null值列表存储的。当前只有一个 VARCHAR 字段,需要用 1 个 bit 标记它的 null 值组成 null 值列表,mysql 要求 null 值列表最少需要一个字节,所以需要占用 1 个字节),又因为 VARCHAR 列的长度是可变的,需要 1 到 2 个字节(字符长度超过 255,则使用两个字节)用于存储字符串的长度信息。
所以支持的最大长度是 65535 - 2 = 65533,如果允许为 null 则是 65532。
以上是字节数,实际的字符又取决于使用的字符集。
- UTF-8 字符集:每个字符最大占用 3 字节(但也可以是 1 字节、2 字节或 3 字节,具体取决于字符的实际编码)。因此,最大字符数会受限于字符集的编码方式。如果使用 UTF-8,最大字符数大约是 21844 字符(65533 ÷ 3)。
- UTF-16 字符集:每个字符通常占用 2 字节。最大字符数大约是 32766 字符(65533 ÷ 2)。
- Latin1 字符集:每个字符占用 1 字节,所以最大字符数为 65533 字符。
在定义 VARCHAR(n) 时,n 代表的是字符的个数,而不是字节数。