必须用char:字段长度恒定(如md5/sha256哈希、国家代码、性别码)、实际值远小于定义长度时char更省空间(因varchar至少多占1字节长度标识)、需启用pad_char_to_full_length保留填充空格。

选 CHAR 还是 VARCHAR,不看“习惯”或“看起来更短”,只看三个硬指标:字段长度是否稳定、实际值是否远小于定义长度、是否需要保留末尾空格。
什么时候必须用 CHAR
固定长度且无变化的字符串,CHAR 不仅省事,还更稳。
- MD5/SHA256 哈希值:如
CHAR(32)存 MD5,CHAR(64)存 SHA256 —— 长度恒定,CHAR避免长度前缀开销,索引也更紧凑 - 国家代码(ISO 3166-1 alpha-2)、性别码(
'M'/'F')、状态标志('ACT'/'INA')—— 都是 2–3 字符,CHAR(2)比VARCHAR(2)在 InnoDB 行格式下实际更省空间(VARCHAR至少多占 1 字节长度标识) - 启用
pad_char_to_full_length=ON的场景(如某些金融系统审计要求显式保留空格填充)—— 此时CHAR的填充行为是可控的,而VARCHAR根本不支持这种语义
什么时候该用 VARCHAR
VARCHAR 不是“默认选项”,而是为真正变长的数据准备的;乱设大长度反而拖慢性能。
- 用户名、地址、标题等长度波动大的字段:如
VARCHAR(50)存用户名,95% 的值在 5–20 字符之间 —— 空间节省明显,且现代 MySQL(8.0+)对短VARCHAR的查询优化已很成熟 - 需要保留末尾空格的业务数据:比如某配置项值为
'on '(带空格),用CHAR(3)插入后查出来是'on'(自动 trim),而VARCHAR(3)能原样保留 - 字段定义长度 > 255 字符:直接不能用
CHAR(最大只支持 255),只能选VARCHAR或TEXT - 注意长度陷阱:
VARCHAR(500)并不比VARCHAR(50)“更安全”—— 如果实际值平均只有 15 字符,前者会让 MySQL 在内存排序、临时表、索引前缀计算时预留更多空间,增加 buffer pool 压力
CHAR 和 VARCHAR 在索引与比较中的实际差异
别信“CHAR 一定更快”这种笼统说法,关键看操作类型和数据分布。
- 等值查询(
WHERE col = 'ABC'):如果列上建了 B-Tree 索引,CHAR因长度固定,优化器更容易做范围估算;但差距在百万级以下数据中通常不到 5%,VARCHAR并非瓶颈 - 排序(
ORDER BY)或分组(GROUP BY):CHAR字段的 sort buffer 占用可预估,VARCHAR则需动态解析每行长度,极端情况下(大量接近上限长度的值)可能触发磁盘临时表 - 隐式类型转换风险:
CHAR字段参与JOIN或WHERE时,若对比值是字符串字面量(如'123'),MySQL 会按列定义长度补空格再比较;而VARCHAR不补——这可能导致看似相同的值在CHAR上匹配失败(例如CHAR(5)存'123'实际是'123 ',跟'123'比较返回 false) - 索引长度限制:InnoDB 默认单列索引前缀上限是 767 字节(utf8mb4 下约 191 字符),
VARCHAR(255)建索引默认只索引前 191 字符;CHAR(255)同样受限,但因长度固定,有时更容易被误判为“全字段可索引”
容易被忽略的字符集与行格式影响
同一个 VARCHAR(10),在不同配置下物理存储可能差一倍以上。
- 字符集决定单字符字节数:utf8mb4 下一个中文字符占 4 字节,
VARCHAR(10)最多存 10 字符 ≈ 40 字节;latin1 下则最多 10 字节。而CHAR的空间占用直接乘以这个字节数(CHAR(10)+ utf8mb4 = 固定 40 字节) - InnoDB 行格式影响溢出行为:使用
DYNAMIC或COMPRESSED行格式时,过长的VARCHAR值(如超过页大小一半)会自动转为行外存储,此时和TEXT行为趋同;但CHAR永远不会溢出,强制留在行内 —— 这可能让单行尺寸失控,触发Row size too large错误 - 严格模式(
STRICT_TRANS_TABLES)下,超长插入对两者都报错;但非严格模式下,CHAR会静默截断并填充空格,VARCHAR截断后不补空格 —— 这种静默行为在线上容易引发数据一致性问题
真正难的不是选 CHAR 还是 VARCHAR,而是得先清楚业务数据的真实长度分布、查询模式、以及当前 MySQL 版本和配置下的实际行为边界。拿不准时,用 SELECT AVG(LENGTH(col)), MAX(LENGTH(col)) FROM tbl 看一眼真实值长度,比查文档管用。











