首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >mysql存储字符使用char"好"还是varchar"好"

mysql存储字符使用char"好"还是varchar"好"

原创
作者头像
大大刺猬
发布2026-04-30 14:14:29
发布2026-04-30 14:14:29
1080
举报
文章被收录于专栏:大大刺猬大大刺猬

节前,水一篇

导读

mysql存储字符串通常使用char/varchar, 那么使用哪个"更好"呢?

我们需要注意的是, char虽然是定长, 但定长的是字符数,而不是字节数, 存储的是字符编码之后的字节, 那么存储的空间就和字符集挂钩了;

通常会使用utf8mb4字符集, 该字符集表示: Most Byte 4 即最多使用4字节, 也就是一个字符使用1-4字节来表示.(utf8mb3就是最多使用3字节).

所以char实际上占用的字节数也是一个范围(不考虑myisam的fixed格式, 那玩意硬是给你补到most)

由于char会填充空格,所以char无法存储空格; 取数的时候是否去掉空格和sql_mode的pad_char_to_full_length有关,

存储空间

从存储空间上看看这俩的区别:(我们主要看Innodb存储引擎).

存储范围

char存储的时候会先补充空格' '后(binary是填充'\x00')再编码存储, 所以char(n)实际使用字节数为: n - n*Maxlen

varchar存储的时候直接编码后存储, 所以varchar(n)实际使用的字节数为: 0 - n*Maxlen

Maxlen: 某字符集一个字符最多使用的字节数量.

我们来看例子:

代码语言:sql
复制
create table db1.t20260430_char01(
id int primary key,
c1 char(5)
);
insert into db1.t20260430_char01 values(1,'x');
create table db1.t20260430_varchar01(
id int primary key,
c1 varchar(5)
);
insert into db1.t20260430_varchar01 values(1,'x');

从存储范围来讲, varchar更优. 但若取极限,比如char(1)和varchar(1)这种场景呢?

存储长度

对于存储变长字符,往往需要使用额外的空间来记录实际占用的长度, char的范围是0-255字符, varchar范围是0-65535字符,也就是需要1-3字节才能表示这个范围, 但mysql一个页最多就64k, 所以实际上最多只需要2字节即可.

对于char(n)/varchar(n),如果 n*Maxlen不超过255的话, 就使用1字节表示; 若n*Maxlen超过255的话,就使用1-2字节表示,具体规则为:若第一字节高位为1(>=128)则使用2字节,否则使用1字节.

所以实际上char和varchar存储的元数据信息都是一样的. 但是有个例外, 若char使用的是单字节字符集(比如latin1),则char(n)存储范围是n - n*1, 即不需要存储元数据信息, 这时候会比同等的varchar少1字节的元数据.

存储定长字符

从存储空间来看, varchar几乎完败char, 那么如果存储的是定长字符呢? 毕竟char就是为定长字符设计的. 比如:

代码语言:sql
复制
create table db1.t1(
	uuid char(32) charset latin1
);

create table db1.t2(
	uuid varchar(32) charset latin1
);

从存储上讲, t2表会比t1表多1字节, char略胜一筹; 但char修改长度(官方)不支持instant, 万一以后存在扩展的情况,就不方便修改长度了(其实可以加1列).

其实,实现char修改instant不难:

代码语言:sql
复制
-- 5.7的表结构信息在frm文件, 创建个一样的表,然后alter修改相关字段,然后把frm文件拷贝回去即可
create table db2.t1(
	uuid char(32) charset latin1
);
alter table db2.t1 modify uuid char(64) charset latin1;
cp -ra /data/mysql_5744/mysqldata/db2/t1.frm /data/mysql_5744/mysqldata/db1/t1.frm
代码语言:shell
复制
# 8.0 使用我们之前编写的offline ddl脚本(要重启), 之前限制的是varchar,所以需要把这个限制个给注释掉(哪里报错注释哪里)
python3 offline_ddl_instant_modify_column.py /data/mysql_8037/mysqldata db1.t1.uuid 64

不建议这么修改, 不然可能会出现这么诡异的一幕

总结

只有极个别特殊情况使用char才会好一丢丢, 可以直接忽略. 省流: 使用varchar"更好"

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • 存储空间
    • 存储范围
    • 存储长度
  • 存储定长字符
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档