varchar(255)与varchar(20)性能差异显著:排序时按声明长度预分配内存(utf8mb4下分别为1022字节/行和82字节/行),索引key_len大幅增加导致b+树效率下降,且255触发1字节长度标识而256需2字节,影响存储对齐与页内碎片。

不一样,而且差别很实在——不是“理论上不同”,而是MySQL在排序、临时表、索引等关键路径上,会按声明长度(255或20)预分配内存,而不是按实际存了几个字符。
ORDER BY 或 GROUP BY 时内存按声明长度预分配
MySQL 对 VARCHAR 字段做排序或分组时,不会看“你实际只存了 'abc'”,而是直接按定义的 N 分配缓冲区空间:
-
VARCHAR(20)→ 按最多 20 字符预留空间,utf8mb4 下最多占20 × 4 + 2 = 82字节/行(+2 是长度前缀) -
VARCHAR(255)→ 同样逻辑,最多占255 × 4 + 2 = 1022字节/行 - 若表有 5 个
VARCHAR(255)字段,仅这 5 列就可能吃掉约 5KB 内存/行(用于 sort buffer 或 tmp table),而同语义字段用VARCHAR(20)可压到 400 字节以内
索引 key_len 直接体现声明长度的影响
建索引后执行 EXPLAIN,key_len 值会暴露底层开销:
-
VARCHAR(20)+ utf8mb4 + 允许 NULL →key_len = 20 × 4 + 1 + 2 = 83 -
VARCHAR(255)+ utf8mb4 + 允许 NULL →key_len = 255 × 4 + 1 + 2 = 1023 - 这意味着:B+ 树每页能存的索引记录数锐减,树深度增加,范围查询和回表效率下降
- 组合索引中,过大的前导列会直接“挤掉”后续列的生效机会(比如
(name, status),name占满 1023 字节,status几乎无法被高效利用)
VARCHAR(255) 和 VARCHAR(256) 的存储长度标识差异
虽然你问的是 255 vs 20,但这个边界值常被误用,顺带说清:
-
VARCHAR(255)→ 长度信息用 1 字节 存储(0–255) -
VARCHAR(256)→ 长度信息强制升为 2 字节(哪怕你永远只存 10 个字符) - 单行省 1 字节不显眼,但千万级表 + 多变长字段,就是 MB 级冗余,且影响 InnoDB 行格式对齐和页内碎片
真正容易被忽略的点是:这些开销在日常 INSERT/SELECT 中几乎无感,只有当数据量上去、开始跑报表、加 ORDER BY、建联合索引、或遇到 “Row size too large” 错误时,才突然爆发。别等报错再回头改字段长度——定义时就该按业务最大合理值来,比如邮箱用 VARCHAR(254),不是因为 255 顺口,而是 RFC 5321 明确上限;手机号用 VARCHAR(16),不是因为“够用”,而是它真就 11–16 位(含国际区号和分隔符)。











