在使用utf8字符编码的情况下:
char(11) 用来存储手机号,会占用11 bytes
bigint 用来存储手机号,会占用 8 bytes
varchar(11)用来存储手机号,会占用 12 bytes
从容量和速度上看,bigint是最好的选择。
从扩展性上看,如果有国际区号,业务上也不会带着国际区号去查询,国际区号也可以放在另一列。
因此,为什么不使用bigint存储手机号呢?
手机号一般是要加索引的吧。。bigint你用了like索引就失效了
1.首先,手机号的本质是字符串而不是数字,只是恰巧长得像数字而已。(网上百度的,我也不知道三大运行商是怎么储存的)
2.字符串可以通过LINK去匹配,查询很方便。
3.字符串可以去匹配尾号或者首号。
4.在32位的某些应用中,bigint太大,会溢出,要进行各种转换,很麻烦。
5.手机号可能有-(座机),用int存不了。
char(32) | varchar(32) | |
---|---|---|
占用空间 | 固定 32 字符(如果数据长度不够 32 将用空格补齐) | 跟随实际存储内容长度,但不超过 32 |
空格处理 | 检索时会去掉尾部空格(数据本身有空白符也会被去掉) | 不会对空格处理 |
是否记录字段长度 | 否 | 是。额外拿出空间记录字段数据长度(字符数) |
适用场景 | 存储的数据长度基本一致,不需要空格,eg 手机号、UUID、密码加密后的密文 | 数据长度不一定,长度范围变化较大的场景 |
bigint的优势有:
更小的空间占用;
更高的操作效率(待验证);
支持更多的操作,比如between and操作;
VARCHAR的优势:
灵活;设计时候可以指定最大长度,存储时,存多少占用多少;
CHAR的优势:
效率比varchar更高;
假设我们将字段内容设计为 地区编码(4位)+手机号或者区号座机号(11位)的格式,那么该字段内容固定位15位长度:
空间:
bigint:8字节
VARCHAR:15字节
CHAR:15字节
bigint > varchar = char
效率猜测:
bigint > char > varchar
扩展性:
bigint:最多19位,实际使用15位,还有至少3位扩展空间(最高位如果拿来用时,其他位是有可能溢出的)
varchar:扩展性根据创建时候指定
char:没有扩展性
varchar > bigint > char
测试结果反转了我对操作效率的认知,实际为:
varchar >= char > bigint;
这样一来,char唯一可能的优势(效率)就不复存在了,bigint的优势也只剩下:
空间占用;
支持between and操作;
对于bigint的优势,对其进行分析:
空间占用:对于一个存放4位区号(不太可能,这里取4位为了计算最大的空间占用差距)和11号码的bigint和varchar,一个号码bigint 8Byte,varchar 15Byte,差距7Byte,假设中国是精确的十三亿人口,每人存放一条手机号码信息:差距就是:9100000000Byte,换算一下不到8.5GB,数据冗余备份共3个副本的话,就是25.5GB;节省的空间相当有限,因为其本身占用空间就不大,相信这个空间节省很难打动一个拥有13亿数据量的应用,将手机号存储切换至bigint;
这还是考虑到4位区号的情况下,如果不考虑区号,不计算副本,空间节省将变成不到3.7GB;实在难以让人心动;
支持between and操作这个优势,varchar也能使用正则表达式来实现相同的功能;或许在这一点上,bigint效率会高于varchar?这也许又是另一个话题了,但无论如何,bigint始终没有达到我对插入、查询方面的效率改进的预期;
综上,bigint没有足够多的优势打动我去使用bigint存储手机号,虽然很不甘心,当初次萌生这个想法的时候是相当兴奋的,觉得好像发现了新大陆,但是不得不将使用bigint存放手机号这个想法给打消;或许下次我应该试试使用int来存储手机号;
不存储区号;如果需要区号,分库或者分表的要求是非常合理的;甚至服务器本身都不会在同一个地区;
省略手机号开头的1(国内还没有看到1以外的数字开头的手机号,国外情况未知),这样就只剩下10位了,依然不够,第二位从0到9分库分表,还剩下9位,这对于int来说,能够存储了;
我一直认为对于数字的处理,交给数字类型比较好,所有才会有这样的想法,int对比varchar总该有性能提升吧;当然这样做,也有局限性:
实现起来变麻烦了,不过对于13亿数据量来说本身就应该分表了,一张表200w数据后就可能操作起来显著变慢;可是涉及到所有有手机号的字段都需要建立0~9 10个分表,这实在是代价有点大;也不能varchar和int混用,否则int那点可能存在的效率上的优势会被转换消化掉;
没有扩展性,如果将来手机号演变为2开头,那就麻烦啦;当然按照人口发展规律,可能性不大;但是另一个恐怖的念头展现在我脑海中了,那就是物联网,如果要给每个接入物联网的设备一个唯一号码呢?那int实现的扩展性将是致命的;
分析下来,int或许有些许性能优势,但其带来的复杂度和扩展上的劣势让我根本都不必动手,就打消了念头了;唉,也许这就是为什么大多数公司选择varchar存储手机号的原因吧;