VARCHAR(N)和CHAR(N)的N均指字符个数而非字节数;VARCHAR长度可变,CHAR固定长度;VARCHAR(255)与VARCHAR(100)存储开销相同,但超255字符时长度头由1字节增至2字节。
MySQL 中 VARCHAR 和 CHAR 的长度到底指什么
它指的是字符个数,不是字节数——但前提是字符集是 utf8mb4(mysql 8.0 默认);如果用 gbk,一个汉字占 2 字节,varchar(10) 仍表示最多存 10 个字符,只是底层占 20 字节。别被“最大长度 65535 字节”这种文档说法带偏:那是行总长度限制,不是单字段上限。
-
VARCHAR(N)的N是字符数,有效范围是 1–16383(InnoDB 行格式下,受页大小和其它字段影响) -
CHAR(N)的N也是字符数,上限是 255;超过会自动转成VARCHAR - 定义
VARCHAR(255)不等于“一定占 255 个字符的空间”,它只存实际内容 + 1 或 2 字节长度头(≤255 字符用 1 字节头)
什么时候该用 CHAR,什么时候必须用 VARCHAR
CHAR 只在长度高度固定、且很短时有优势,比如国家代码 CHAR(2)、性别 CHAR(1);其余场景基本都该用 VARCHAR。用错的典型表现是:把用户名设成 CHAR(32),结果每条记录都浪费 28+ 字节(假设平均只填 4 个字符)。
-
CHAR固定长度,查询时无需解析长度头,但写入/更新更耗空间,尤其配合ROW_FORMAT=COMPACT时可能引发页分裂 -
VARCHAR节省空间,但长度头带来微小开销;MySQL 8.0+ 对短VARCHAR(≤768 字节)默认内联存储,不额外分配溢出页 - 不要为“看起来整齐”而用
CHAR——排序、索引、JSON 输出都不会因此变好看
ALTER TABLE ... MODIFY 调整长度的坑
改大一般安全,改小极危险:如果已有数据超长,MySQL 默认拒绝(除非关掉 sql_mode=STRICT_TRANS_TABLES),但即使成功,也会无声截断——你不会收到警告,数据就丢了。
- 执行前务必检查:
SELECT MAX(LENGTH(column_name)) FROM table_name;,注意是LENGTH()(字节数),不是CHAR_LENGTH()(字符数),因为存储空间看字节 - 从
VARCHAR(200)改到VARCHAR(100),若存在 150 字节的值,语句会失败并报错ERROR 1406 (22001): Data too long for column - 加
ALGORITHM=INPLACE也不能绕过校验;想强制截断?别这么干——先用UPDATE清洗数据,再MODIFY
空间计算:为什么 VARCHAR(1000) 比 VARCHAR(100) 多占 1 字节
关键在长度头:≤255 字符用 1 字节存长度,>255 字符用 2 字节。所以 VARCHAR(100) 和 VARCHAR(255) 存储开销一样,但跨过 255 就多 1 字节头——这 1 字节对单行不明显,但百万级表就是近 1MB 额外空间。
- 字符串内容本身按字符集编码存,
utf8mb4下一个 emoji 占 4 字节,一个英文字母占 1 字节 - 行内总长度(所有字段 + 长度头 + NULL 标志位 + 记录头)不能超 65535 字节;超了会把大字段移到溢出页,影响查询性能
- 别迷信“设大点省事”——
VARCHAR(4000)在多数业务字段上纯属预留焦虑,真需要那么长,说明设计可能已偏离常规文本范畴
字符集、行格式、已有数据分布——这三个变量不摸清,光调长度参数就是在碰运气。










