最准结构差异比对应查information_schema.COLUMNS,因其含COLUMN_NAME、DATA_TYPE、IS_NULLABLE、COLUMN_DEFAULT(NULL转'NULL')、COLUMN_COMMENT、ORDINAL_POSITION、EXTRA等完整列元数据,且不受SHOW CREATE TABLE的顺序、默认值、注释格式等干扰。

查 information_schema.COLUMNS 比字段定义最准
结构差异本质是列元数据不一致,information_schema.COLUMNS 里存着所有关键字段:COLUMN_NAME、DATA_TYPE、IS_NULLABLE、IFNULL(COLUMN_DEFAULT, 'NULL')、COLUMN_COMMENT、ORDINAL_POSITION(顺序不同也算差异)、EXTRA(比如 auto_increment 或 on update CURRENT_TIMESTAMP)。直接查它,不依赖外部工具,也不受 MySQL 版本弃用影响。
常见错误现象:用 SHOW CREATE TABLE 字符串比对,结果一堆“差异”但实际结构一致——因为字段顺序可能被 ALTER 重排、AUTO_INCREMENT=123 是运行时值、注释空格/换行/反引号风格不统一、ENGINE 和 CHARSET 默认值会被隐式补全。
- 跨库比对必须加
WHERE TABLE_SCHEMA = 'db_name',否则会混入mysql、sys等系统库结果 -
COLUMN_DEFAULT为NULL时要统一转成字符串'NULL',否则显式DEFAULT NULL和空默认值会被当成不同 - 别漏
ORDINAL_POSITION:主键字段从(a,b)改成(b,a)是语义差异,但字符串 diff 很难识别
用 GROUP_CONCAT 生成结构指纹快速判断是否一致
如果只要知道「是不是完全一样」,不用逐字段核对,拼接标准化签名最快。执行这条 SQL:
SELECT GROUP_CONCAT(CONCAT(COLUMN_NAME,':', DATA_TYPE,':', IS_NULLABLE,':', IFNULL(COLUMN_DEFAULT,'NULL'),':', IFNULL(COLUMN_COMMENT,''),':', EXTRA) ORDER BY ORDINAL_POSITION SEPARATOR';') AS sig FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'db1' AND TABLE_NAME = 't1';
对另一张表(如 db2.t1)执行同样语句,两个 sig 结果复制出来直接用 == 或 diff 命令比即可。
- 必须加
ORDER BY ORDINAL_POSITION,否则字段顺序不同就误判 -
IFNULL(COLUMN_DEFAULT, 'NULL')不可省:NULL 值和显式 DEFAULT NULL 在语义上等价,但原始值不同 - 这个签名不包含索引、外键、分区——这些需单独查
information_schema.STATISTICS、KEY_COLUMN_USAGE等表
查 information_schema.TABLES 校验引擎和字符集
information_schema.COLUMNS 只管字段,不管 ENGINE、TABLE_COLLATION、AUTO_INCREMENT 这些表级属性。而 ENGINE=InnoDB 和 ENGINE=MyISAM 混用会导致事务失效、SELECT FOR UPDATE 静默忽略、外键约束不校验等 runtime 行为错乱。
执行:
SELECT table_schema, table_name, engine, table_collation FROM information_schema.tables WHERE TABLE_SCHEMA IN ('db1', 'db2') AND TABLE_NAME = 't1';对比两行中 engine 和 table_collation 是否完全一致。注意:SHOW CREATE TABLE 里写的 ENGINE=MyISAM 可能已过时——MySQL 8.0+ 隐式转为 InnoDB 后,元数据中的 engine 字段才是真相。
- 别信
SHOW VARIABLES LIKE 'default_storage_engine':它只影响新建表,不改造存量表 - 升级后务必跑一次:
SELECT table_schema, table_name, engine FROM information_schema.tables WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys') AND engine != 'InnoDB';,有结果就得人工确认是否仍被业务读写
用 UNION ALL + GROUP BY + HAVING 定位数据行差异
结构兼容(列数、类型、顺序可对齐)的前提下,这是最直接的全量差异定位方式。把两张表用 UNION ALL 拼起来,按所有比对字段分组,再筛出只出现一次的行:
SELECT * FROM ( SELECT col1, col2, col3 FROM db1.t1 UNION ALL SELECT col1, col2, col3 FROM db2.t1 ) AS u GROUP BY col1, col2, col3 HAVING COUNT(*) = 1;
它不依赖主键,也不要求字段名一致,只要 SELECT 列能一一对应即可。
- 必须显式写出所有参与比对的列,不能写
*(除非两张表字段完全一致且顺序相同) -
GROUP BY的字段必须和SELECT中的非聚合列完全一致,否则 MySQL 8.0+ 会报错 -
NULL值在GROUP BY中被视为相同,但多条NULL行会导致COUNT(*) > 1,从而漏掉真实差异 - 字符串字段注意隐式转换:比如
CHAR和VARCHAR末尾空格处理不同,可能让本该相同的行被当成差异
真正麻烦的不是怎么比,而是比完之后发现 EXTRA 里多了个 on update CURRENT_TIMESTAMP,或者 table_collation 差了个 _as_cs 后缀——这种细节不会报错,但会在某个并发高峰或迁移时刻突然暴露。


















