项目开发时,需要先行设计数据库。不得不说,做程序开发这一行,经验实在太重要了,所以在设计数据库时,大多数人是凭经验去设定数据表各个字段的数据类型,比如主键id一般为int(10) unsigned primary key, 也有的是为int(11) unsigned primary key。这样问题就来了,为什么是选择int(10),有的选择int(11)?是有什么客观条件约束,抑或是“之前都是这么设计的“?int(10),int(11)也困扰了我好久,现在就来再次研究一下这其中的区别。
1. 先介绍下MySQL的int类型相关数据类型
(1). mysql数据库中对整型分为5个不同的小类型,分别是tinyint、smallint、mediumint、int和bigint,主要区别是数据库存储时使用几个字节,也就是说限定整数的范围,上述类型存储使用的字节为1、2、3、4和8。取值范围可以根据字节数来算出来。注意:它们都可以指定为无符号(大于等于零)的整数。
类型 | 字节数 | 最小值(有符号) | 最大值(有符号) | 最小值(无符号) | 最大值(无符号) |
tinyint | 1 | -128 | 127 | 0 | 255 |
smallint | 2 | -32768 | 32767 | 0 | 65535 |
mediumint | 3 | -8388608 | 8388607 | 0 | 16777215 |
int | 4 | -2147483648 | 2147483647 | 0 | 4294967295 |
bigint | 8 | -9223372036854775808 | 9223372036854775807 | 0 | 18446744073709551615 |
(2). 不同的数据类型的所占用的字节数是不同的,而一个字节包含8个byte(二进制位:0,1),所以也就是说tinyint由 1个字节数 * 8个byte = 8个二进制位 组成,所以这8个二进制位能表示的数值的范围就是tinyint其所能存储的值的范围。
(3). 再比如说,int类型占4个字节,就是32个byte,
有符号时: -2^31 (-2,147,483,648) 到 2^31 – 1 (2,147,483,647)
无符号时:0到2^32(4294967295)
(4). 二进制有符号位和无符号的差别在于:第一位表示正负, 第一位是0表示是正数,1表示是负数
无符号数: 1111 1111 值:255,
1* 2^7 + 1* 2^6 + 1* 2^5 + 1* 2^4 + 1* 2^3 + 1* 2^2 + 1* 2^1 + 1* 2^0 = 255
有符号数: 0111 1111 值:127 ,有符号位时,第一位不参与运算,只表示正负
1* 2^6 + 1* 2^5 + 1* 2^4 + 1* 2^3 + 1* 2^2 + 1* 2^1 + 1* 2^0 = 127
对于给定一个二进制数,无法判断是有符号还是无符号,有符号无符号是人为指定的,就如mysql中给可以明确指定字段类型是不是有符号无符号(unsigned),设定好,在根据有无符号位,做相应的逻辑处理。
2.重点来了,int(10),int(11)的区别在哪儿呢?
上面已经说了,int类型占4个字节,32个byte,其能存储的数值范围已经是确定了的了!!!
也就是说不管int(10),int(11),这个点类型已经定了是int,其存储范围是完完全全相同的!!!
那int(10),int(11)括号里的又数字表示什么呢? 答:显示宽度,
那什么是显示宽度呢?请继续往下看
说再多,不如一个demo来的实在:
这里我用Navicat新建一个test1表,包含2个字段a tinyint(1), b tinyint(3),并且插入两条数据
然后,我们去查询这两条数据,我这里直接用的yii框架。里面的bin是mysql自带的函数,mysql的bin()函数能计算出这个值原始存储的二进制数。
查询结果如下:
一切正常,bin(a),bin(b)也是a,b的二进制数
然后修改下刚才的表结构,字段b还是tinyint(3),不过下面的填充零点上,既是tinyint(3) zerofill,然后在看下查询数据
上面的查询结果,已经能看出些不同了,在设定字段b填充零后,查出来的结果与之前就发生了变化,之前是‘1’变成了‘001’,之前是‘12’就变成了‘012’,这里我们就再说一下显示宽度这个概念,显示宽度只有和字段有zerofill这个属性结合起来才有意义。
这样说,字段b为tinyint(3),显示宽度为3位,如果没有zerofill,没什么影响,如果有了zerofill就有了变化。当存储的数据长度未达到字段设定的显示宽度(这里是3),mysql就会自动的在数据的左侧填充 0,已达到设定的显示宽度,所以说,原来的数值 1,长度只有1位,没有达到设定的显示宽度3,所以mysql自动将其填充为‘001’,但是其原始存储的二进制数据,没有任何变化,这只是‘应用层’的一个处理。这样说,应该能明白显示宽度了吧。
再说一下int(10)和int(11) 的问题,很多时候程序开发是为了解决极值(边界)问题,上面已经说到无符号位int最大存储值是 42 9496 7295(42亿多,数字是10位),一般情况下设计数据表时,主键id一般都会设为int,但是int最大为42亿多,我们不去怀疑有的很大型的项目,可能会达到这么大的数据量,但是更多的项目根本达不到这个数据量,可能连mediumint(1677 7215,1千6百多万)都达不到,但是“经验”告诉我们还是要设为 int
int(10)或int(11)显示宽度都已经能涵盖了int整个取值范围了,如果没有zerofill,就基本上没有任何差别了,如果有的话,就会自动填充到显示宽度,不过这样的话,int(10)只有10亿(10位数字)考上的不会发生填充0情况,int(11)所有的都会发生填充0 的情况(毕竟int最多也就10位数字)。不过呢,在数据库表的设计中一般不会给字段设定填充0的(起码,我没这样设计过)。
All of the above, int(10),int(11)只是一个显示宽度的问题,其所能存储的范围是一样的。如果字段没设定zerofill的话,没有任何差别!
That's it!