前几天,我又去面了一家公司。作为一个有点小资历的31岁程序员,面试这种事儿其实早就习惯了,但每次还是有种“打怪升级”的感觉。
刚坐下来,面试官微微一笑,递过来一道经典面试题:
“那我们来个热身吧,你能说说 CHAR 和 VARCHAR 的区别吗?”
当时我心里咯噔一下:这题,真的是“老生常谈”啊!但同时,我也知道,这是很多社招面试官特别喜欢用来“划水+试探”的问题。看似简单,答得深,能看出你的底子和经验;答得浅,就容易被贴上“只会写CRUD”的标签。
所以,我干脆就把自己这几年踩过的坑、见过的项目问题,全都搬了出来。面试官笑眯眯地听着,最后点点头:“不错,你是真吃过亏的人。”
于是今天,我就把这段经历写出来,和你们聊聊 CHAR 和 VARCHAR 的区别,顺便讲讲里面那些容易忽略的细节。希望对准备面试的你有点帮助。
故事开头:项目中的“神奇Bug”
大概三年前,我在一家电商公司,做会员中心那块。某天,我们遇到一个超级诡异的问题:
会员表里有个 phone 字段,本来存的都是手机号,结果有用户反馈说:我注册时手机号写错了,改了之后,居然还能登录老账号?!
我们查数据库一看,明明手机号已经更新了,可是某些查询居然还能命中原本的手机号!
团队里炸开了锅。有人说是不是缓存没更新?有人说是不是代码逻辑有bug?但我仔细盯着表结构一看,立马发现了端倪:
对,字段居然用的是 CHAR。
于是我马上试了个实验:存进去一个手机号 1381234567(注意,只有10位),结果查出来变成了 1381234567␣(最后多了一个空格)。原来,CHAR 是定长的,不管你写多少,它都要填满长度!
再一查代码逻辑,发现有些地方用 = 比较手机号时,没做 trim,于是各种“幽灵手机号”就出现了。最后我们改成 VARCHAR(11),问题才算彻底解决。
从那以后,我对 CHAR 和 VARCHAR 的区别,再也没敢掉以轻心。
面试中的“标准答案”
好,先把最直白的区别列一下,这是面试官一般想听到的点:
1、存储方式不同
- CHAR:定长,长度固定。不足会补空格,超长会截断。
- VARCHAR:变长,按实际长度存储,还会额外占用 1~2 个字节记录长度信息。
2、存储效率不同
- CHAR:因为是定长,存储和读取效率高,适合存放长度固定的数据(比如身份证号、MD5值、国家代码)。
- VARCHAR:存储空间更节省,但在更新时可能会引起数据页分裂,导致性能下降。
3、空间占用不同
- CHAR(n) 永远占用 n 个字符空间。
- VARCHAR(n) 最多占 n 个字符 + 1~2 个字节(用于存储长度)。
4、尾部空格的处理
- CHAR 会自动补空格,查询时 MySQL 会自动忽略这些空格。
- VARCHAR 则不会自动补空格,保存什么就是什么。
到这一步,其实就能拿到“及格分”了。但如果只答到这,还不够打动面试官。那怎么办?很简单——继续深入。
进阶回答:实际应用场景
这才是能让面试官眼前一亮的地方。
- 什么时候用 CHAR?
- 固定长度的字段: 比如:身份证号(18位)、性别(M/F)、国家代码(CN/US/JP)
- 高频查询的字段: 因为定长,查询速度比 VARCHAR 要快一点点,尤其在索引上更稳定。
- 什么时候用 VARCHAR?
- 长度不确定的字段: 比如昵称、邮箱、地址、手机号。
- 节省存储空间: 如果字段内容长短差别特别大,CHAR 会浪费大量空间,这时候就用 VARCHAR。
- “混搭”策略
在实际项目中,有些团队喜欢把所有字符串字段都统一成 VARCHAR,图省事。但更讲究的做法是:
- 对确实固定长度的字段,用 CHAR。
- 对变化较大的,用 VARCHAR。
- 而且要结合 查询频率、字段大小 来权衡。
举个例子:
- 用户表里 gender → CHAR(1)。
- 用户表里 nickname → VARCHAR(50)。
- 用户表里 phone → VARCHAR(11)(因为有些国家手机号不一定11位)。
深入一点:存储引擎的差异
面试官如果继续追问:“那在 InnoDB 里,它们的存储方式有什么不同呢?”
这个时候,很多人就开始紧张了。
其实很简单:
1、InnoDB
- CHAR:定长存储,空间固定。
- VARCHAR:变长存储,数据存在页里,但太长会放到溢出页上。
2、MyISAM(虽然现在少见了,但面试官有时会考)
- 对 CHAR 和 VARCHAR 的处理方式不同,VARCHAR 在 MyISAM 里不太会引起性能问题,但在 InnoDB 里就要小心页分裂。
换句话说,很多人说 VARCHAR 比 CHAR 慢,实际上那是早期 MyISAM 的印象,在 InnoDB 里差别并没那么大。
再来点“骚操作”
我还遇到过一个挺有意思的场景。
有一次我们做一个日志表,里面有个字段是 status,表示日志状态,本来就只有几种:success、fail、pending。
一开始有人定义成了 VARCHAR(20),后来 DBA 看了直摇头:
“这种字段,完全可以用 CHAR(1) 存个数字,比如 0、1、2,再在代码里映射,不仅省空间,索引效率也高。”
后来一算,日志表一共几十亿条记录,光是这个字段就能省下好几个 G 的空间。
所以说,字段类型设计,其实是很考验经验的事儿。
答题模板总结
最后,我给你们一个“标准面试答案模板”,如果你在面试的时候被问到,就可以这样回答:
1、定义
- CHAR:定长字符串,不足补空格,查询时会去掉尾部空格。
- VARCHAR:变长字符串,按实际长度存储,多占 1~2 字节记录长度。
2、区别
- 存储方式不同:CHAR 定长,VARCHAR 变长。
- 空间占用不同:CHAR(n) 总是 n,VARCHAR(n) 取决于实际长度。
- 查询效率不同:CHAR 稍快,VARCHAR 节省空间但可能有额外开销。
3、应用场景
- 固定长度、高频查询 → 用 CHAR。
- 变长、节省空间 → 用 VARCHAR。
4、扩展点
- 在 InnoDB 里,VARCHAR 太长可能溢出到溢出页。
- 在索引里,CHAR 的对比更高效。
- 设计时要考虑存储空间和查询效率的权衡。
这样一套下来,不仅显得你基础扎实,还能表现出项目经验。
结尾
说到底,CHAR 和 VARCHAR 的区别,很多人只停留在“一个定长一个变长”上,但真正的考点,是你能不能结合实际场景去分析。
毕竟,面试官想要的不是教科书,而是能解决问题的人。
就像我当年踩过 CHAR 的大坑一样,有了血泪教训,再遇到这道题,答案自然就不一样了。
所以,下次当你被问到这道题的时候,不妨也讲一个你自己的故事——那才是最打动人的答案。
END
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!