这个问题,说实话是那种看起来简单,其实越想越拧巴的典型代表——“面试官:20亿手机号存储选 int 还是 string?varchar 还是 char?为什么?”
先别急着答,咱慢慢捋一捋。要不然分分钟被面试官带沟里。
首先,很多同学第一反应是:“手机号不就是数字么?int不香吗?”兄弟,想想咱平时手机号写着写着就得加个区号,国际号啥的,甚至有些国家的手机号前面有“+”,你这int存个“+”试试?直接寄。
再来,int 的最大值是 2^31 - 1,也就是 2147483647,手机号动不动就是 11 位数,一些国家甚至更长(比如印度13位),你用int存简直是请Bug来跳舞。不信你试试这段代码:
public class PhoneTest {
public static void main(String[] args) {
int phone = 13812345678; // 编译直接报错:整数太大
System.out.println(phone);
}
}
👆你看,连Java编译器都不让你犯这个错。
那用 long 行不行?行是行,但你得注意几个点:
-
long
最大值是 2^63-1,能装得下手机号。 -
但你要是跨国业务、搞啥国际化,就不够用了,手机号可能带国家码、前缀符号(+)啥的,那你这玩意儿还能叫号码?
讲真,我在一个金融项目里踩过坑,客户手机号有“+86”、“+44”,存long的话只能先strip(去掉符号和前缀),结果后来有个需求要显示原始手机号,一堆数据直接没法还原...最后我们一怒之下,全转string了。
说到string,那varchar和char怎么选?
这俩的区别是老生常谈了:
-
char(N)
:定长,不足补空格; -
varchar(N)
:变长,实际占多少就存多少。
你可能会说,手机号都是11位的,char不是更好?我劝你别太天真...
虽然手机号长度表面上看似固定,但:
-
未来不确定,比如有些国家扩展到了12位;
-
有些业务系统手机号会带前缀,存的是“+8613812345678”,你char(11)够用吗?
-
用char会不会浪费空间?当然会,如果你按char(20)来定义,那实际用11位,空着9位,每条记录浪费9字节,20亿条记录就是180G,谁来背这口大锅?
而varchar
就灵活多了,真正用多少存多少,字段长度设成20甚至30都不怕,多余的不占空间。现在的存储系统处理varchar也没以前那么慢,别被“char快”这个老黄历洗脑了,那都是老掉牙的理论了。
我之前做CRM系统优化时,客户数据里有手机号、邮箱、微信ID,我们一开始偷懒用char(50)统一搞定,结果数据库膨胀得像吃了膨化剂...后来改成varchar,容量直接缩了三分之一,查询速度还提升了(索引页小了,缓存更快了)。
还有一个很重要的点:你是不是要对手机号建索引?如果建索引,varchar和char在B-Tree结构上的存储方式就影响很大了。char会多占空间,影响索引层级深度,导致查询IO变多。
那你说用string/varchar,那性能会不会差?以前可能是,但现在数据库的优化做得越来越好了,字符串的性能瓶颈没那么大了,反而因为灵活性和可扩展性成了首选。
讲真,现在谁还在用char存手机号,十有八九是祖传数据库结构没敢改。
当然了,也不是说string就是银弹。要是你做的是那种极端优化场景,比如电信级别的C级应用,手机号作为主键高频操作,每秒几百万TPS,那你可能要考虑“压缩存储”、“phone number normalization”等骚操作,甚至把手机号转成hash做存储,那就是另外一套玩法了。
不过多数业务场景,varchar完全够用了,简单可靠,迁移扩展也方便。
总结一下哈,选型我个人是这么认为的👇:
-
int/long:不靠谱,除非你只做中国本地且只存纯数字,还得小心前导0被吃掉;
-
char:能不用就别用,浪费空间还不灵活;
-
varchar:推荐首选,灵活,兼容性强,未来扩展也不慌。
最后扯一嘴题外话,很多面试官问这个问题,其实根本不在乎你说的是int还是string,他是想看看你对存储结构、扩展性、性能的综合理解。所以回答时千万别上来就说“我选int,因为int效率高”,这会让人觉得你经验太少、考虑问题太表面。
面试不是答标准答案,而是看你能不能从实际业务出发,做出有依据的技术决策。
说到底嘛,技术选型这事儿,没有绝对的对和错,只有是否适合场景。别为了“省几个字节”搞得数据还原不了,那就真成笑话了。