CHAR适合存固定长度且极短的字段如国家代码、性别、MD5值;VARCHAR节省空间但需警惕行大小限制和空格语义差异;TEXT专用于大文本,避免行内膨胀但有IO和索引限制。

CHAR适合存固定长度且极短的字段
比如国家代码(CHAR(2))、性别(CHAR(1))、MD5哈希值(CHAR(32))这类长度完全可控的数据。MySQL对CHAR的处理是直接分配满额空间,不计算实际长度——这反而让InnoDB定位行更快,尤其在大表全表扫描或排序时,定长结构减少CPU解包开销。
常见错误是把用户昵称设成CHAR(50):哪怕只存3个字,也硬占50×字符集字节数(UTF8MB4下就是200字节),严重浪费Buffer Pool空间;更糟的是,如果该列参与ORDER BY或GROUP BY,MySQL会按填充后的完整长度做比较,可能引发隐式转换或索引失效。
- 严格限制n ≤ 255,超出会被MySQL自动转为
VARCHAR并报warning - UTF8MB4下
CHAR(10)永远占40字节,和存“a”还是存“你好世界”无关 - 除非启用
pad_char_to_full_length模式,否则SELECT查出来自动TRIM()掉尾部空格
VARCHAR必须明确长度上限且警惕行大小限制
VARCHAR不是“随便写个大数就完事”。它的最大长度受MySQL单行65535字节总限制约束,且实际可用长度取决于字符集和表中其他字段。例如UTF8MB4下,一个汉字占4字节,VARCHAR(20000)理论上需要80000字节,早超限了——这时MySQL会静默转成MEDIUMTEXT,但你建表语句里写的还是VARCHAR,容易误判存储行为。
典型陷阱是定义VARCHAR(65535):即使单字段也没用,因为还要预留NULL标志位、长度前缀、其他字段空间。实测中,只要表里还有几个INT或DATETIME,VARCHAR能用的有效长度往往不到20000。
- n ≤ 255时,长度前缀占1字节;n > 255时,强制占2字节——别小看这1字节,百万级表里就是近1MB额外存储
- InnoDB默认行格式(
COMPACT)下,VARCHAR超过页半(约8KB)会触发溢出存储,带来额外IO - 建索引时,
VARCHAR字段只能索引前767字节(旧版本)或3072字节(MySQL 8.0+ withinnodb_large_prefix=ON)
尾部空格保留与否直接影响业务逻辑
这是最常被忽略的语义差异:CHAR存'abc '(末尾带空格),查出来变成'abc';VARCHAR存同样的值,查出来还是'abc '。如果你的业务依赖空格判断(比如密码盐值、协议字段分隔符、日志原始格式),用错类型会导致比对失败。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
更隐蔽的问题在WHERE条件里:WHERE name = 'x '对CHAR列永远为true(因自动trim),但对VARCHAR列只匹配真实带空格的记录。线上曾有订单状态字段用CHAR(10)存'pending ',后来改成VARCHAR后,老代码没改trim逻辑,导致状态查询全部失效。
- 测试方法:插入
'a '(a加空格),用LENGTH()和CHAR_LENGTH()对比结果 - 应用层若已习惯trim,数据库层再用
CHAR会掩盖空格问题,但换库或迁移时极易暴露 - MySQL 8.0+的
pad_char_to_full_length=ON可关闭自动trim,但需全局配置,影响面广
TEXT类型不该是VARCHAR的“放大版”
看到字段可能超长,第一反应不是把VARCHAR(255)改成VARCHAR(65535),而是问:它真需要索引全文?是否频繁读取全部内容?如果只是偶尔存长文本(如用户反馈、错误堆栈),TEXT更合适——它不占主行空间,避免行溢出拖慢整页访问。但代价是无法直接ORDER BY或GROUP BY整个字段,且索引只能建前缀(如content(255))。
反例:把商品描述设为VARCHAR(10000),结果90%记录只用200字,却让每行凭空多占9800字节+2字节前缀,Buffer Pool迅速被无效数据塞满,QPS断崖下跌。
-
TEXT系列(TINYTEXT/TEXT/MEDIUMTEXT)本质是行外存储,主键查询时多一次IO -
VARCHAR在InnoDB里仍属“行内字段”,哪怕很长,只要不溢出就比TEXT快 - 真正该用
TEXT的信号:字段平均长度 > 1000字节,且>70%的查询只读前几百字
实际选型时,别只看“长度是否固定”这个表面特征。关键要抠三点:字段在查询中的参与方式(是否排序/索引)、空格是否携带业务含义、以及它和其他字段组合后的行大小压力。很多性能问题,根源不在单个类型选错,而在没算清这三笔账。










