跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何对比MySQL中的CHAR和VARCHAR存储差异_通过长度固定与溢出页

CHAR始终按声明长度固定分配空间且不溢出,VARCHAR按实际长度存储并支持溢出页;CHAR(1)与VARCHAR(1)在单字节字符集下物理占用相近,但utf8mb4下CHAR仍固定、VARCHAR可变;CHAR受PAD_CHAR_TO_FULL_LENGTH影响读取行为,VARCHAR不受影响。 CHAR和VARCHAR的存储长度固定性差异在哪 CHAR字段在InnoDB中**始终按声明长度分配空间**,哪怕只存1个字符。比如
CHAR(32)
存
'a'
,实际仍占32个字符位置(utf8mb4下最多128字节),尾部用空格填充;而
VARCHAR(32)
只存
'a'
时,仅用1字节数据 + 1字节长度标识 = 2字节(长度≤255时)。 关键不是“有没有空格”,而是InnoDB行格式是否允许压缩或溢出——
CHAR
因长度固定,无法触发行溢出;
VARCHAR
则可能触发: 当单个
VARCHAR
字段内容长度 > 页内剩余空间(通常约8KB)时,InnoDB会把超长部分移入溢出页,行内只留20字节指针
CHAR
永远不溢出,哪怕
CHAR(1000)
(虽然语法上只允许≤255,但逻辑上它“拒绝变长”) 即使
VARCHAR
声明长度很大(如
VARCHAR(65535)
),只要实际内容短,就不会溢出 溢出页只对VARCHAR生效,CHAR完全不参与 InnoDB的溢出页(off-page storage)机制只针对可变长度列,且前提是该列实际数据长度超过阈值(约768字节)。
CHAR
类型被设计为“不可溢出”:它的长度在建表时就固化,引擎不会为它生成20字节指针,也不会拆分存储。 这意味着: 如果误用
CHAR(255)
存短文本(如UUID),会浪费大量空间,且无法利用溢出优化
VARCHAR(255)
存同样UUID,实际只占37字节(32字符+5字节长度标识?不,utf8mb4下32字符最多128字节,长度标识仍为1字节),更省空间也更灵活 一旦某
VARCHAR
列实际写入超长内容(比如一段base64图片),InnoDB自动启用溢出页,避免单行撑爆16KB页限制 为什么CHAR(1)和VARCHAR(1)在存储上几乎没差别 当声明长度极小(如1–255)且字符集为单字节(
latin1
)时,
CHAR(1)
和
VARCHAR(1)
物理占用都是1字节——前者无填充开销(因为刚好满),后者无长度标识冗余(1字节长度标识+1字节数据 = 2字节,但
CHAR(1)
也是1字节+隐式长度信息?不,
CHAR
不存长度标识)。 MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 但真实场景中这个“几乎没差别”很脆弱: 换到
utf8mb4
后,
CHAR(1)
可能占1–4字节(取决于字符),但依然固定;
VARCHAR(1)
则按实际字符字节数 + 1字节标识
CHAR(1)
无法存空字符串
''
(会被转成单个空格),而
VARCHAR(1)
可以 如果字段要索引,
CHAR(1)
索引效率略高(定长跳转快),但差距微乎其微,不构成选型依据 别忽略PAD_CHAR_TO_FULL_LENGTH对CHAR的干扰 默认情况下MySQL检索
CHAR
会删掉尾部空格,看起来和
VARCHAR
一样;但一旦开启
PAD_CHAR_TO_FULL_LENGTH
模式(比如某些ORM或BI工具强制设置),
CHAR
返回值就会带满填充空格,导致字符串比较、JSON序列化、前端渲染出问题。 这种模式切换不改变存储,只改读取行为,却常被忽略: 应用层代码假设
CHAR(10)
返回
'abc'
,但开了该模式后实际是
'abc '
(7个空格)
VARCHAR
完全不受此SQL mode影响,行为稳定 线上环境排查时,容易误判为数据写入异常,其实是读取侧SQL mode漂移

相关文章