今天排查了一个看起来很小,但很容易把人带偏的问题。
同一张业务表、同一个主键字段 id,在两套本地开发环境里看到的 SHOW CREATE TABLE 结果不一样:
-
Windows 11 本地 MySQL
8.0.12显示为bigint(20) unsigned
-
WSL2 Ubuntu 24.04 本地 MySQL
8.0.45-0ubuntu0.24.04.1显示为bigint unsigned
如果只是扫一眼,很容易以为两边 schema 不一致,甚至怀疑某次迁移没有跑齐,或者某个环境被手工改过字段类型。更麻烦的是,这个字段还是主键自增列。只要涉及 unsigned、auto_increment、外键关联,经验上就不能靠猜。
所以这次没有继续停留在图形界面,而是直接回到数据库本身,把问题拆成三层来看:
SHOW CREATE TABLE到底返回了什么information_schema.columns里的元数据到底是什么- 这两个版本之间,MySQL 官方是否改过整数类型的输出规则
我最后确认到的结论是:这不是 schema 差异,而是 MySQL 小版本差异导致的 DDL 输出差异。
先说现象
两边的真实建表语句,除了主键字段的显示方式不同,其余部分一致。抽象成一个最小示例如下。
Windows 11,MySQL 8.0.12:
CREATE TABLE `example_table` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
WSL2,MySQL 8.0.45-0ubuntu0.24.04.1:
CREATE TABLE `example_table` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
如果只盯着这一行,直觉上会觉得少了一个 (20),像是字段定义发生了变化。但继续往下查 information_schema.columns 后就会发现,真正关键的属性并没有变:
DATA_TYPE仍然是bigintCOLUMN_TYPE仍然保留unsignedEXTRA仍然是auto_increment- 主键属性没有变化
也就是说,影响行为的部分没有变,变的是 MySQL 输出 DDL 的方式。
关键变化发生在 MySQL 8.0.19
这件事的分界点不是 “Windows 和 WSL2”,也不是 “Navicat 和命令行”,而是 MySQL 8.0.19。
MySQL 官方文档给出的时间线很清楚:
- 在 MySQL
8.0.17,整数类型的 display width 已被标记为 deprecated - 到 MySQL
8.0.19,SHOW CREATE、DESCRIBE以及相关INFORMATION_SCHEMA输出中,默认不再显示整数 display width - 例外主要是
TINYINT(1)和带ZEROFILL的整数类型
这正好解释了这次现象:
8.0.12仍然沿用旧行为,所以SHOW CREATE TABLE输出bigint(20) unsigned8.0.45已经包含8.0.19之后的行为,所以SHOW CREATE TABLE输出bigint unsigned
这不是字段被改窄了,也不是 unsigned 丢了,更不是自增列定义发生了变化。只是 MySQL 从 8.0.19 开始,默认不再把整数 display width 打印出来。

为什么还能查到“20”
排查时还有一个容易让人困惑的点:明明新版 SHOW CREATE TABLE 里已经不显示 (20) 了,为什么从 information_schema.columns 里还能查到 NUMERIC_PRECISION = 20?
原因是,这两个 “20” 不是一个概念。
旧版 SHOW CREATE TABLE 里看到的 bigint(20),说的是整数 display width,这个语法历史很长,但它本来就不决定存储大小,也不改变值域。
而 information_schema.columns.NUMERIC_PRECISION = 20,反映的是这个数值类型的精度元数据。对于 BIGINT UNSIGNED,最大值是:
18446744073709551615
这是一个 20 位十进制数字,所以 precision 是 20。这部分元数据保留,并不意味着新版 MySQL 还在用 display width 参与字段定义展示。
所以这次排查里最值得记住的一点是:
SHOW CREATE TABLE看到的是当前版本如何“打印”DDLNUMERIC_PRECISION看到的是数值类型本身的精度元数据
两者都可能出现 20,但语义并不相同。
这类差异会不会影响业务
如果两边真实语义一致,只是一个显示为 bigint(20) unsigned,另一个显示为 bigint unsigned,那对业务没有实际影响。
不会受影响的部分包括:
- 主键自增行为
- 存储字节数
- 索引行为
- 外键兼容性
- Laravel 这类框架里
id()、foreignId()的匹配关系
真正应该关注的不是 (20) 在不在,而是下面这些属性是否一致:
- 是否都是
bigint - 是否都带
unsigned - 是否都为
NOT NULL - 是否都启用了
AUTO_INCREMENT - 主键和外键定义是否一致
如果这些都一致,那么这类差异就是“显示差异”,不是“结构差异”。
这次排查留下的一个习惯
以后再遇到跨环境对比表结构的问题,我会尽量先跳过 GUI 的直觉判断,优先做三件事:
SHOW CREATE TABLE example_table;
SELECT VERSION();
SELECT
COLUMN_NAME,
COLUMN_TYPE,
DATA_TYPE,
NUMERIC_PRECISION,
COLUMN_KEY,
EXTRA
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'your_database'
AND TABLE_NAME = 'example_table'
AND COLUMN_NAME = 'id';
先确认版本,再确认 DDL,再确认元数据。这样能比较快地把“显示差异”和“真实 schema 差异”分开,不会被一个 (20) 带着跑偏。
今天这个问题不算大,但很适合记下来。因为它提醒我一件很基础、但也很容易在忙的时候忘掉的事:数据库问题里,字符串长得像不像,经常没有语义是否一致重要。
参考资料
- MySQL 8.0.19 Release Notes
https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-19.html - MySQL Numeric Data Type Syntax
https://dev.mysql.com/doc/refman/en/numeric-type-syntax.html - MySQL Worklog WL#13528: Remove integer display width from SHOW CREATE output
https://dev.mysql.com/worklog/task/?id=13528
[DRAFT_RESTORED]
已恢复你上次未提交的评论草稿。
草稿仅保留在当前标签页;提交成功后会清空,关闭标签页后会自动失效。