MySQL char 和 varchar 的区别是什么?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于 Spring AI + Spring Boot3.x + JDK 21...点击查看;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot3.x + JDK 17...点击查看项目介绍; 演示链接: http://116.62.199.48:7070/;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

面试考察点

面试官提出这个问题,不仅仅是希望你记住两种数据类型的定义,更是为了考察:

  1. 基础概念理解:是否清楚 CHARVARCHAR 最核心的 “定长” 与 “变长” 区别。
  2. 存储机制掌握:是否了解 MySQL 底层如何存储这两种类型的数据,这关系到对 存储空间、I/O 性能 的理解。
  3. 实际应用能力:能否根据具体的业务场景(例如存储固定长度的身份证号、或长度多变的用户昵称)做出正确的类型选择,这体现了设计表时的 实践经验和性能考量
  4. 细节关注度:是否了解一些关键细节,例如 VARCHAR 的长度限制(65535 字节)、不同字符集(如 utf8mb4)下的实际字符数限制,以及 CHAR 在存储时会去除尾部空格等行为。

核心答案

CHARVARCHAR 是 MySQL 中最常用的两种字符串类型,其核心区别在于 存储方式

  • CHAR(N)定长字符串。无论实际存储的字符串多长(即使只存了1个字符),它都会固定占用 N 个字符的存储空间。如果不足,会用空格在尾部填充。
  • VARCHAR(N)变长字符串。它只会占用实际字符串长度 + 额外长度标识的存储空间。这个 “额外长度” 用于记录字符串有多长。

因此,对于长度固定或波动极小的数据(如国家代码 CHAR(2), MD5 哈希值 CHAR(32)),使用 CHAR 更高效。对于长度变化大的数据(如用户名、文章标题),使用 VARCHAR显著节省存储空间

深度解析

原理/机制

  1. CHAR 的存储
    • 分配固定的 N 个字符宽度。
    • 存储时,如果数据长度小于 N,会在右侧用空格填充到指定长度。
    • 检索时,会自动去除尾部填充的空格(但在比较时,空格处理有细微差别,依赖于 PAD_CHAR_TO_FULL_LENGTH SQL Mode)。
  2. VARCHAR 的存储
    • 采用“长度前缀 + 实际数据”的紧凑格式。
    • 如果长度 <= 255 字节,前缀用 1 个字节 表示;否则用 2 个字节。这就是为什么 VARCHAR(255) 是一个常见的设计节点。
    • 存储的是精确的字符串内容,不会填充空格。

代码示例

以下 SQL 示例清晰地展示了行为差异:

-- 创建测试表
CREATE TABLE test_string (
    col_char CHAR(10),
    col_varchar VARCHAR(10)
);

-- 插入相同数据
INSERT INTO test_string VALUES ('abc', 'abc');

-- 查询数据长度(注意CHAR类型的返回值)
SELECT 
    col_char, 
    CHAR_LENGTH(col_char) as char_len, -- 结果为 3,因为检索时去除了尾部空格
    col_varchar, 
    CHAR_LENGTH(col_varchar) as varchar_len -- 结果为 3
FROM test_string;

-- 验证存储空间占用(近似方法,不同引擎有差异)
-- 对于 ‘abc’:
--   col_char 固定占用 10 字符(例如 utf8mb4 下为 10*4=40 字节)
--   col_varchar 占用 3字符 + 1字节长度前缀 = 13 字节(utf8mb4)

对比分析与最佳实践

维度CHAR(N)VARCHAR(N)
本质定长变长
存储空间固定 N * 字符集最大字节长度。存储短字符串时有空间浪费。实际字符数 * 字符集字节数 + 长度前缀(1或2字节)。更节省空间。
存取速度理论上更快。因为是固定长度,磁盘寻址和内存计算更简单。稍慢。需要根据长度前缀计算实际位置,但在现代硬件下差异很小。
尾部空格存入时填充,检索时自动去除(比较时需注意)。原样存储和检索,不会去除
适用场景长度固定或几乎不变的数据:
• 枚举代码(如性别 M/F
• 固定长度的哈希值(MD5, UUID)
• 邮编、国家代码
长度变化较大的数据:
• 用户名、邮箱地址
• 文章标题、摘要
• 任何无法确定长度的文本字段

最佳实践建议

  1. 优先使用 VARCHAR:在绝大多数业务场景中,字符串长度都是可变的,使用 VARCHAR 是最佳选择,能有效节省存储,尤其是表数据量巨大时。
  2. 明确使用 CHAR 的场景:只有当你百分之百确定该字段长度绝对固定时,才使用 CHAR。例如 CHAR(32) 存储 MD5 值。
  3. 关于长度 N 的设置VARCHAR(N)N 指的是最大字符数,而非字节数。在 utf8mb4 字符集(每个字符最多占 4 字节)下,一个 VARCHAR(255) 字段理论最大占用约 255 * 4 + 2 = 1022 字节。

常见误区

  • 误区一:“CHAR 一定比 VARCHAR 快”:这个结论在小表或简单查询中不明显。VARCHAR 的紧凑存储减少了磁盘 I/O,有时反而更具优势。性能差异应通过实际压测判断。
  • 误区二:“VARCHAR 最大长度就是 65535”:这是最大字节数限制。一个 VARCHAR 列的实际最大字符数受限于所选字符集。例如在 utf8mb4 下,单列最大字符数约为 (65535 - 2) / 4 ≈ 16383
  • 误区三:过度放大类型选择的影响:在早期架构设计和 SQL 优化中,关注点应优先放在索引设计、查询语句、范式与反范式上。在确认这些是瓶颈后,再考虑此类微观优化。

总结

简单来说,CHAR 是“用空间换时间”的定长类型,适合存储长度绝对固定的字典码;而 VARCHAR 是“用计算换空间”的变长类型,适合存储长度不确定的通用文本,这也是现代数据库设计中更主流和推荐的选择。