MySQL int(10) 与 int(11) 的区别
不知道大家是不是和我一样,每次给有个列添加 int(11)
的时候都会想,会不会是 int(10)
,偶尔也会发神经的想,如果 int(32)
这样的可否?
这个纠结,恐怕我写完读完这篇文章时还会继续
索性,我们就先来解决这个问题吧。
在前面一章节中我们有提到,int
类型的底层存储采用的是 4
字节,也就是 32 位,这样能够存储的实际最大值为 4 294 967 296
,大家数数一下这个数字,总共有多少位 ?
对的,没错,就是 10
位,所以,感觉 int(11)
这个应该是错误的 ? 实际上,真的错了吗 ?
没有,因为我们演示的是无符号整型的情况,而对于有符号整型,范围是 -2 147 483 648
到 2147483648
,大家数一数最小值,是不是就 11 位了
所以,int(11)
就是这么来的,而且也不会错。
但这到底是什么道理呢 ?
为了搞清楚弄明白,我们就必须去了解 MySQL 是如何对待数据类型上的属性的。
数值类型的宽度显示属性
对于所有的数值类型,MySQL 通过扩展的方式,可以有选择性的在类型的 base 关键字后面的括号中指定 「 整数 」 数据类型的 「 显示宽度 」 。
注意: 我们使用 「」 括号扩起来的 整数 和 显示宽度 两个词。
例如,例如,INT(4)
指定显示宽度为 4 位的 INT
。对于一个类型为 INT(4)
的列,实际存储仍然使用 4 个字节,但显示的时候就有有细微的差别:
- 如果给该列传递的值大于等于四位,比如
5201314
,那么显示的时候会使用原值,也就是显示5201314
- 但如果给该列传递的值小于四位,比如
520
,那么显示的时候就会在左边填充0
,也就是显示位0520
我们举一个例子,假设我们有一个表如下
CREATE TABLE `na` ( n1 INT(4) NOT NULL DEFAULT '0', n2 INT(4) ZEROFILL NOT NULL DEFAULT '0' );
然后插入一些数据
mysql> INSERT INTO `na` VALUES(520,520),(5201314,5201314); Query OK, 2 rows affected (0.04 sec) Records: 2 Duplicates: 0 Warnings: 0
最后我们看看显示的结果
mysql> SELECT * FROM `na`; +---------+---------+ | n1 | n2 | +---------+---------+ | 520 | 0520 | | 5201314 | 5201314 | +---------+---------+ 2 rows in set (0.01 sec)
对比下 n1 和 n2 ,n1 是不是在位数不满足的时候会填充前导的 0
。
从演示结果上来看,显示宽度不会限制可以存储在列中的值的范围,也不会阻止比列显示宽度更宽的值正确显示。例如刚刚的范例,指定为 INT(4)
的列的取值范围为 -2 147 483 648
到 2147483648
,超过四位数允许范围之外的值将使用四位数以上显示
当列添加了 ZEROFILL
约束时 ( 注意,这并不是 SQL 标准的一部分 ),会使用 0
代替默认的默认的空格 ' '
。例如,对于声明为 INT(4) ZEROFILL
的列,会将值 5 显示为 0005
注意
在表达式或 UNION 查询中涉及列时,会自动忽略 ZEROFILL 属性。
使用 ZEROFILL 属性时要注意,如果将大于显示宽度的值存储在具有 ZEROFILL 属性的整数列中,为某些复杂连接生成临时表时可能会遇到问题。因为在这些情况下,MySQL 会假定数据值符合列显示宽度
数值类型的 UNSIGNED 显示属性
所有整数类型都可以具有可选 ( 非标准 ) 属性 UNSIGNED
。无符号类型可用于仅允许列中的非负数或当需要更大的列的上限数字范围时。例如,如果 INT 列为 UNSIGNED,则列的范围大小相同,终端显示时范围从 -2147483648
和 2147483647
更改为 0
和 4294967295
。
从某些方面说,就是 UNSIGNED 属性并不会更改底层的数据存储格式,仍然是 SIGNED
有符号整数,但在显示时,会将有符号的值自动转换为无符号的值。也就是说 UNSIGNED
也是一个显示属性
浮点和精确精度类型也可以是 UNSIGNED
,与整数类型一样,此属性可防止负值存储在列中。但与整数类型不同,列值的上限范围保持不变。
数值类型的 ZEROFILL 显示属性
ZEROFILL 列的属性,我们刚刚介绍过了,这里就不重复介绍了。
如果为数值列指定了 ZEROFILL
,MySQL 会自动添加 UNSIGNED
属性到列中。
数值类型的 AUTO_INCREMENT 属性
整数或浮点数据类型可以添加附加属性 AUTO_INCREMENT
。如果某个列添加了 AUTO_INCREMENT
属性,那么在插入数据的时候,如果不指定该列或者指定该列的值为 NULL
,那么 MySQL 会自动将该列的值设置为下一个序列值
通常,值为 value+1
,其中 value
是表中当前列的最大值。
注意:
AUTO_INCREMENT
序列以1
开始而不是 0
另一个需要注意的是,将 0
存储到 AUTO_INCREMENT
列与存储 NULL
具有相同的效果,除非启用了 NO_AUTO_VALUE_ON_ZERO SQL
模式。
而对于插入 NULL
以生成 AUTO_INCREMENT
值需要将列声明为 NOT NULL
。如果列声明为 NULL,那么插入 NULL
将存储 NULL
。
还有一个需要注意的是,当你将任何其它值插入 AUTO_INCREMENT
列时,该列将设置为该值并重置序列,以便从插入的值开始按顺序执行下一个自动生成的值。所以千万要避免在 AUTO_INCREMENT
指定列值插入,很大概率会发生主键重复的问题
在 MySQL 8.0 及以上的版本, AUTO_INCREMENT
列会自动添加一个隐式的 UNSIGNED
属性来保证插入的值非负。