char类型强制填充空格造成空间冗余:定义char(n)即固定占用n字符位置,存'a'也补19空格占20字节;utf8mb4下更甚,char(10)恒占40字节,存3汉字时70%为浪费;行大小限制65535字节加剧拆表或误用varchar;尾部空格仅查询时隐藏,length、like、备份均暴露真实冗余;其性能优势仅在真等长且高频随机访问时成立。

CHAR类型强制填充空格导致空间冗余
CHAR(n)不是“最多存n个字符”,而是“必须占满n个字符位置”。哪怕只存一个字母,MySQL也会用空格补足到n字节。比如CHAR(20)存'a',实际写入的是'a '(19个空格),占用20字节——这部分空格不是“看不见的数据”,而是真实写入磁盘的冗余字节。
utf8mb4字符集下浪费被进一步放大
CHAR按“字符数”定义长度,但存储按“字节数”实际占用。在utf8mb4字符集下,一个汉字占4字节,而CHAR(10)仍会固定分配10 × 4 = 40字节,不管里面存的是1个字还是10个字。如果字段平均只存3个汉字,那近70%的空间就是纯空格+预留字节浪费。
行大小限制让浪费产生连锁影响
MySQL单行最大65,535字节(不含BLOB/TEXT)。大量CHAR字段会快速吃掉这个限额,迫使你:
- 不得不把本可合并的字段拆到多张表
- 或降级为VARCHAR却保留过大上限(如VARCHAR(255)),反而失去长度约束意义
- InnoDB页内紧凑存储对CHAR更友好,但前提是“真固定”;若业务数据其实参差不齐,这种友好就变成负优化
尾部空格自动去除掩盖了问题严重性
SELECT时MySQL默认去掉CHAR字段尾部空格,让人误以为“没存那么多”,但以下场景暴露真相:
- SELECT LENGTH(col)返回的是定义长度(如20),不是内容长度
- WHERE col = 'a'能匹配'a ',但WHERE col LIKE 'a%'可能因填充空格意外匹配更多行
- 备份/导出时,空格全量写入SQL文件,体积膨胀肉眼可见
真正容易被忽略的是:CHAR的“快”只在全字段等长且高频随机访问时成立;一旦长度波动超过20%,它的空间税和隐式截断风险(超长值直接被砍)就远大于那点微弱的定位优势。











