int(20),bigint(20)中的20是什么含义 - mysql整型数据显示宽度
TL;DR
int(M)里面的M,对当今的业务开发没有用,不要写,写int就可以了。其他整数类型同理。而且这个特性在未来的mysql版本中会被废弃。
稍微详细一点的解释
对于mysql的整型数据(tinyint,smallint,mediumint,int,bigint),类型后面括号里面的数字M表示显示宽度(display width)。对于我们的编程工作,这个数字实际上没有任何意义。它只是一个提示(hint),提示客户端怎么显示这个数字,对于数据存储以及数据读取没有任何的影响,而且客户端也可以甚至应该,忽略这个提示。
但是在实际中这个写法很容易让大家产生一个误解,误以为M是一个限制。我们会理所当然的认为,如果我写了int(4),那么这个字段最大存储就是9999,存10000是会出问题的。
上面这个理解是非常错误的。对于myqsl的整型字段占用的存储空间以及能存储的最大最小值,只与定义的整型类型有关系,因此,即使你定义一个字段是int(4),你还是可以用这个字段存取10000,甚至更大,只要它没有超过整型最大值2147483647。int(4),int(11),int(20),用起来没有任何区别,都一样。
mysql的整型类型取值范围,可以参照如下官方文档
https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
显示宽度到底怎么起作用
为了更好的理解这个问题,澄清我们的误解,我们回答下显示宽度如何起作用。
我们在使用mysql查询数据的时候,mysql在返回数据的同时还会返回一个数据集元数据(result set metadata),我们定义的显示宽度的值就会包含在这个元数据中,我们的应用程序通过读取这个元数据得知当初建表的时候,对于这个字段预期的最大长度是多长,这样方便程序展示数据时做一些对齐的工作。以上就是显示宽度的作用。
在定义显示宽度的时候,我们还可以定义一个叫zerofill的属性,这个属性的含义是当你的数据长度不足你定义的长度时通过在左侧补0来补齐宽度。比如我们定义了int(4)的字段,存储了数据1,那么查询时应该显示001,同样,zerofill也包含在数据集元数据中。同时需要注意的是,如果你给一个整型字段加了zerofill属性,mysql会自动帮你加上unsigned属性。
下面我们通过一个示例来看看mysql是怎么返回显示宽度的。
建表,我们定义了一些显示宽度不同的字段
create table case_of_display_width
int_width5_no_zerofill int(5) null,
int_with20_no_zerofill int(20) null,
int_width20_zerofill int(20) unsigned zerofill null,
int_without_width int null
插入如下数据
INSERT INTO case_of_display_width VALUES (123456, 123456, 123456, 123456);
使用mysql命令行时加上显示语句元数据的参数--column-type-info
mysql -uusername -ppassword --column-type-info
查询并查看返回
mysql> select * from case_of_display_width;
Field 1: `int_width5_no_zerofill`
Catalog: `def`
Database: `show_case_schema`
Table: `case_of_display_width`
Org_table: `case_of_display_width`
Type: LONG
Collation: binary (63)
Length: 5
Max_length: 6
Decimals: 0
Flags: NUM
Field 2: `int_with20_no_zerofill`
Catalog: `def`
Database: `show_case_schema`
Table: `case_of_display_width`
Org_table: `case_of_display_width`
Type: LONG
Collation: binary (63)
Length: 20
Max_length: 6
Decimals: 0
Flags: NUM
Field 3: `int_width20_zerofill`
Catalog: `def`
Database: `show_case_schema`
Table: `case_of_display_width`
Org_table: `case_of_display_width`
Type: LONG
Collation: binary (63)
Length: 20
Max_length: 20
Decimals: 0
Flags: UNSIGNED ZEROFILL NUM
Field 4: `int_without_width`
Catalog: `def`
Database: `show_case_schema`
Table: `case_of_display_width`
Org_table: `case_of_display_width`
Type: LONG
Collation: binary (63)
Length: 11
Max_length: 6
Decimals: 0
Flags: NUM
+------------------------+------------------------+----------------------+-------------------+
| int_width5_no_zerofill | int_with20_no_zerofill | int_width20_zerofill | int_without_width |
+------------------------+------------------------+----------------------+-------------------+
| 123456 | 123456 | 00000000000000123456 | 123456 |
+------------------------+------------------------+----------------------+-------------------+
1 row in set (0.00 sec)
以上可以看到查询返回的元数据,可以看到LENGTH属性,和Flags属性既是我们所定义的显示宽度和zerofill。同时也可以看到对于int(5)的字段,我们仍然可以成功存入和取出123456。
我们现在知道了,显示宽度只是一个显示层需求,它保存的是一个整型字段最大长度的期望而不是强制的限制。它的作用是让客户端展示数据的时候有一个长度参考去做对齐。但是mysql作为一个持久层的工具去关心显示层逻辑似乎不太合理的。mysql自己也意识了这个问题,所以在最新的mysql 8的版本中已经把对整型类型的显示宽度以及zerofill的支持标记为废弃(deprecated ),未来有可能直接移除相关特性。所以,在之后的建表语句中我们就不要声明整型类型的显示宽度了。
https://dev.mysql.com/doc/refman/8.0/en/numeric-type-attributes.html
https://www.computerhope.com/unix/mysql.htm
https://stackoverflow.com/questions/3135804/types-in-mysql-bigint20-vs-int20