char不适合变长字段,因其定长特性导致空间浪费、缓冲池利用率低、i/o成本高;varchar按需分配空间、减少碎片、溢出优化,且现代索引下查询性能无显著劣势,应优先选用。

因为变长字符串用 CHAR 会浪费空间、拖慢写入、增加碎片,而 VARCHAR 在绝大多数场景下更贴合实际数据分布。
CHAR 对变长字段会造成隐性空间浪费
比如定义 CHAR(50) 存用户名,实际只存 "alice"(5 字符),MySQL 仍会分配 50 字符空间,并用 45 个空格填充。这些空格不仅占磁盘,还挤占缓冲池(buffer pool)内存,降低缓存命中率。InnoDB 页面大小固定(默认 16KB),填充空格会让单页能存的行数减少,间接抬高 I/O 成本。
- 空格在检索时通常被自动 trim(除非启用了
pad_char_to_full_length),但存储时已占用资源 - 使用多字节字符集(如 utf8mb4)时,每个字符最多占 4 字节,
CHAR(50)可能实际占用 200 字节,浪费更严重 - 即使字段平均长度接近上限(比如 48/50),只要存在少量短值,整体空间利用率就不可控
VARCHAR 的存储开销远低于 CHAR 的“伪固定”代价
VARCHAR 实际占用空间 = 字符实际字节数 + 1 或 2 字节长度前缀(≤255 字节用 1 字节,否则用 2 字节)。对绝大多数变长文本(昵称、地址、描述),这个额外开销微乎其微,却换来真实按需分配。
- 插入
"tom"到VARCHAR(50),只占 3+1 = 4 字节(utf8mb4 下) - 更新操作不会因“补空格”触发页分裂;而
CHAR频繁更新不同长度值,容易在页内留下无法复用的碎片 - InnoDB 的
ROW_FORMAT=Dynamic下,VARCHAR超过一定长度会自动溢出到单独页,避免撑大主行结构
查询性能差异在现代硬件和索引下并不构成决定性劣势
过去说 CHAR 查找更快,是基于纯全表扫描+无索引场景下“偏移量可直接计算”的优势。但现实中:
- 99% 的查询走的是二级索引或主键查找,行定位不依赖字段长度计算
- 排序、分组操作受
ORDER BY字段是否索引影响远大于CHAR/VARCHAR类型本身 - 真正影响性能的是字段是否参与 WHERE 条件、是否建了合适索引,而不是类型选择
- 如果字段长度波动极大(比如从 1 到 200 字符),
CHAR强制定长反而让统计信息失真,优化器可能选错执行计划
容易被忽略的边界情况:CHAR 并不总比 VARCHAR “快”
很多人默认 CHAR 查询更快,但这个结论成立的前提是:字段长度极短(≤4 字符)、几乎无空格填充、且大量执行无索引的顺序扫描。一旦涉及:
- LIKE 前缀匹配(如
WHERE name LIKE 'a%'),VARCHAR和CHAR行为一致,性能无差别 - 使用函数(如
UPPER(name)),类型差异被完全抹平 - 字段出现在
GROUP BY或JOIN条件中,VARCHAR的比较逻辑与CHAR相同,但CHAR的空格填充可能引入意外相等(比如'abc '和'abc'在某些 collation 下视为相同)
真正该用 CHAR 的只有极少数明确固定长度、无变化可能的字段——比如 CHAR(32) 存 MD5、CHAR(11) 存手机号(且业务层确保格式统一)。其余一律优先 VARCHAR,并合理限制长度(如 VARCHAR(30) 而非 VARCHAR(255)),这才是兼顾空间、维护性和真实性能的做法。











