char适合固定长度且极短的字符串,如国家代码(char(2))、性别(char(1))、md5哈希值(char(32));其定长特性提升索引与排序性能,但空间浪费且不适用含空格语义或可能扩展的字段。

CHAR适合固定长度且极短的字符串
比如国家代码(CHAR(2))、性别(CHAR(1))、MD5哈希值(CHAR(32))这类长度恒定、字符数极少的字段。MySQL对CHAR的内存处理更直接:不需要解析长度前缀,索引定位快,行内存储紧凑。
常见错误是把CHAR(10)用于昵称或城市名——哪怕平均只有4个字符,也会强制补6个空格(单字节字符集下),浪费空间且可能干扰GROUP BY或ORDER BY(尤其在未启用PAD_CHAR_TO_FULL_LENGTH时,检索会自动截断尾部空格,导致语义不一致)。
-
CHAR最大只支持255字符,超长直接报错 - UTF8MB4字符集下,
CHAR(10)实际固定占用40字节(10×4),不是10字节 - 如果业务逻辑依赖末尾空格(如某些协议字段),
CHAR不能用——它一定会删
VARCHAR适合长度变化大或需保留空格的场景
用户昵称、地址、描述文本等天然变长的数据,选VARCHAR是默认合理选择。它只存实际内容+1或2字节长度标识(≤255字符用1字节,否则用2字节),空间利用率高。
但别盲目设大:比如用VARCHAR(200)存邮箱(通常≤50字符),虽然物理存储只多占几字节,但MySQL在内存中按定义长度预分配缓冲区,会导致临时表、排序缓存膨胀,拖慢GROUP BY或ORDER BY性能。
- 修改
VARCHAR长度可能锁表:MySQL 5.7之前全锁;5.7+仅当原长和新长都≤255才免锁 -
VARCHAR索引有767字节限制(InnoDB默认),UTF8MB4下最多索引约191个字符(767÷4) - 更新变长字段可能触发页分裂——特别是频繁增删改且行接近页满时
别用CHAR存“看起来固定”的业务字段
像订单号、身份证号、手机号,表面看长度固定,但实际常含校验位、分隔符或未来扩展可能。例如身份证号现在是18位,但旧系统可能存15位;订单号可能从ORD20230001变成ORD202300001。用CHAR硬编码长度,后续扩容就得改表结构,风险远高于那点存储节省。
真正该用CHAR的,是数据库层面**绝对不变**的约束,比如ISO国家码(US、CN)、HTTP状态码(200、404)、枚举值缩写(ACT、INACT)。这些字段一旦定义,不会因业务演进而变长。
- 用
ENUM或外键替代CHAR枚举字段,可避免拼写错误和长度失控 - 如果字段要参与
JOIN且高频查询,CHAR比VARCHAR略快,但差距通常
TEXT不是VARCHAR的放大版,别乱替
TEXT系列类型(TINYTEXT/TEXT/MEDIUMTEXT)和VARCHAR根本不是同一设计目标:TEXT内容不存于数据页内,而是存于单独的溢出页,行内只留20字节指针。这意味着每次读取TEXT字段都要额外一次I/O,ORDER BY或GROUP BY会强制使用磁盘临时表。
只要字段长度能控制在65535字节以内(UTF8MB4下约16383字符),优先用VARCHAR。只有当明确需要存文章正文、日志块、JSON大对象且长度常超几万字符时,才考虑TEXT。顺便提醒:TEXT列不能设默认值,也不能作为主键的一部分。
-
VARCHAR(65535)受整行大小限制(65535字节是所有列共享的上限),实际可用长度往往更小 - MySQL 8.0+支持
innodb_large_prefix,可突破767字节索引限制,但需调优配置且不解决TEXT的I/O问题
VARCHAR才是安全起点;CHAR是窄门,只留给那些连字符集都敢锁死的绝对定长场景。











