
MySQL中BIGINT与BIGINT(20)主键自增的真正区别:存储、显示与最佳实践
在MySQL数据库设计过程中,BIGINT是一种非常常用的整数类型,尤其适合作为自增主键。不少开发者在创建表时会习惯性地写成BIGINT(20),并且以为括号里的20代表了某种长度限制。其实这里面有一个常见的误解。今天我们就来彻底搞清楚BIGINT和BIGINT(20)到底有什么区别,以及在自增主键的场景下应该如何选择。
一、核心结论:存储空间与数值范围完全相同
首先要明确最关键的结论:无论是BIGINT还是BIGINT(20),它们在MySQL的磁盘上占用的存储空间都是8个字节,也就是64位。这意味着它们能表示的最大值和最小值完全一样,自增主键能够达到的上限也毫无差别。
具体数值范围如下:
- 有符号(默认):从
-9223372036854775808到9223372036854775807 - 无符号(加上UNSIGNED):从
0到18446744073709551615
这么大的范围对于绝大多数业务表的主键来说绰绰有余,即使每秒插入几万条记录,也需要数亿年才能用完。所以,从存储和自增能力的角度看,BIGINT和BIGINT(20)是完全等价的。
很多开发者可能会想,那括号里的20是不是代表可以存储20位数字?其实不是。BIGINT本身最大可以容纳19位(有符号)或20位(无符号)的数字,但括号里的数字并不是用来限制输入位数的。它只是一个显示相关的修饰符,和存储无关。
二、括号里的数字到底是什么
在MySQL 8.0之前的版本中,整数类型后面可以跟一个括号数字,比如INT(11)、BIGINT(20)。这个数字被称为“显示宽度”(display width)。它的作用仅仅是在查询结果显示时,如果数值的位数不够指定的宽度,并且同时使用了ZEROFILL属性,那么MySQL会在数值前面补零,直到总长度等于显示宽度。
举个例子就很容易理解了:
CREATE TABLE test_width (
col1 BIGINT,
col2 BIGINT(20),
col3 BIGINT(20) ZEROFILL
);
INSERT INTO test_width VALUES (123, 123, 123);执行查询后,你会看到:
col1显示为123col2显示为123(因为没有ZEROFILL,显示宽度不生效)col3显示为00000000000000000123(因为指定了ZEROFILL,不足20位时左边补零)
看到了吗?只有当你显式地加上ZEROFILL关键字时,显示宽度才有意义。如果不加ZEROFILL,那么写BIGINT(20)和直接写BIGINT在查询结果上完全一样,没有任何区别。
所以,如果你在建表时只写了BIGINT(20)而没有写ZEROFILL,那么这个20就是多余的,它不会对数据产生任何实质影响。
三、显示宽度的由来与现状
显示宽度这个特性是从MySQL早期版本继承下来的,最初的设计目的是为了让报表或命令行输出看起来更整齐。比如在旧式的管理工具中,所有数字都按固定宽度显示,方便对齐。但随着图形化管理工具和ORM框架的普及,这个特性逐渐失去了实际用途。
更重要的是,从MySQL 8.0.17版本开始,官方已经正式将整数类型的显示宽度标记为废弃(deprecated),并且在未来的版本中可能会完全移除。也就是说,在新的MySQL版本里,你再写BIGINT(20),虽然语法上还能通过,但MySQL会发出警告,提示你该特性即将被移除。
因此,现在的最佳实践是:不要再使用整数类型后面的显示宽度声明,直接写BIGINT即可。这样既符合未来版本的兼容性,也让代码更简洁、语义更清晰。
四、作为自增主键时的最佳实践
既然BIGINT和BIGINT(20)在功能和性能上没有区别,那么在定义自增主键时应该怎么写呢?
推荐的做法是使用BIGINT UNSIGNED AUTO_INCREMENT。理由如下:
- 使用UNSIGNED:主键通常都是非负整数,加上
UNSIGNED可以让取值范围翻倍,从0开始到约1844京,比有符号的上限大了将近一倍。虽然实际中用不到那么多,但这是一个良好的习惯,也避免了负数主键的歧义。 - 省略显示宽度:不再写括号和数字,避免误导和未来兼容性问题。
- 明确AUTO_INCREMENT:自增属性要放在最后。
一个典型的主键定义如下:
CREATE TABLE user (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);这样的写法清晰明了,任何人都能一眼看出这是一个无符号的、自增的BIGINT主键,没有任何冗余信息。
五、常见误区与解答
误区一:BIGINT(20)比BIGINT占用更多空间
完全错误。两者都占用8个字节,括号里的数字不影响存储。
误区二:BIGINT(20)只能存20位数字
BIGINT最多可以存19位(有符号)或20位(无符号),但括号里的20并不是限制位数。实际上,即使你往BIGINT(20)里插入一个21位的数字(如果超出范围会报错),也不会被截断。位数限制是由数据类型本身决定的,不是由括号数字决定的。
误区三:显示宽度会影响索引或排序性能
不会。显示宽度只是一个客户端显示的属性,和索引结构、排序算法没有任何关系。
误区四:新项目中仍然沿用BIGINT(20)的习惯
建议尽快改正。既然官方已经废弃该特性,继续使用只会增加代码的混乱度和未来迁移的成本。养成直接写BIGINT的习惯,既简洁又与时俱进。
六、总结
BIGINT和BIGINT(20)在MySQL中作为自增主键使用时,存储空间、数值范围、自增上限以及性能表现完全一致。括号里的20是早期版本用于控制显示宽度的修饰符,只有在配合ZEROFILL时才会在查询结果中补零,否则没有任何效果。从MySQL 8.0.17开始,显示宽度已被废弃,未来版本将不再支持。
因此,在现在的数据库设计工作中,推荐直接使用BIGINT UNSIGNED AUTO_INCREMENT来定义自增主键,省略任何不必要的显示宽度声明。这样不仅能写出更规范的SQL语句,也能让你的代码更好地适应MySQL的未来发展。希望这篇文章能帮你彻底告别对BIGINT(20)的疑惑,写出更专业、更高效的数据库表结构。