编程 MySQL 9.7 升级后 DDL 被拒:先读 SHOW WARNINGS,再决定用 INPLACE 还是升 9.7.4

2026-11-11 21:08:26

MySQL 9.7 升级后 DDL 被拒:先读 SHOW WARNINGS,再决定用 INPLACE 还是升 9.7.4

MySQL 9.7 是 LTS 系列,GA 日期为 2026-04-21。9.7.4 的 Release Notes 修正了此前一个 InnoDB 改动带来的兼容性问题,但问题本身值得记录:升级后,一批原本能建的表突然建不出来了。

起因:死锁修复让行大小估算变准

9.7.0 的说明里写得很清楚(Bug #39129182):在某些情况下,删除一条记录需要合并 B 树页并更新父页,而 InnoDB 会低估索引记录的大小,导致它以不安全的顺序获取页 latch,可能与并发的 B 树搜索形成死锁。修复方式是更准确地计算最大记录大小,覆盖索引前缀字段和空间 GEOMETRY 索引,从而能提前拿到所需 latch。

代价是 DDL 侧:CREATE TABLE / ALTER TABLE 的行大小校验随之变严,一些超出 InnoDB 文档限制的表定义被正确拒绝——但对已有应用来说,这些定义以前是能通过的。

到 9.7.4,多数 DDL 恢复旧的校验行为,只在防止 B 树死锁确实需要的地方保留精确估算。例外是 ALTER TABLE ... ALGORITHM=INSTANT:它继续使用更严格的计算,以便安全处理较大的默认值。

症状

升级后跑迁移脚本,可能出现两类现象:

  • CREATE TABLE 或 ALTER TABLE 直接报错,语句被拒;
  • 语句执行成功,但产生告警,表结构与预期不一致。

两种都先别改表结构。

第一步:读 SHOW WARNINGS

SHOW WARNINGS;

在同一个会话里紧跟 DDL 执行,否则告警会被后续语句冲掉。告警文本会指出是哪一列、哪个索引相关的行大小估算触发了限制。先确认触发点是列定义、前缀索引还是默认值,再决定动作。

区分新建表与已有表

这两类情况的处理路径不同:

  • CREATE TABLE 新建表:没有历史包袱,优先按告警调整定义(缩短变长列、拆分大字段、收敛前缀索引长度),而不是靠切换算法绕过。
  • ALTER TABLE 已存在的表:表定义是线上正在跑的,不能随手改。此时才考虑显式指定算法。

INSTANT 为什么仍然严格

ALGORITHM=INSTANT 只改元数据、不重建表,因此必须在大默认值写入之前就确认行大小不会越界——它没有机会在后续操作中补救。9.7.4 保留这条路径的严格计算,是有意为之,不是遗漏。

核对列定义

先看原始定义,重点是大变长列、前缀索引和默认值:

SHOW CREATE TABLE app.orders;

再用 information_schema 量化:

SELECT COLUMN_NAME, DATA_TYPE,
       CHARACTER_MAXIMUM_LENGTH, CHARACTER_OCTET_LENGTH,
       COLUMN_DEFAULT, EXTRA
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'app' AND TABLE_NAME = 'orders'
ORDER BY ORDINAL_POSITION;

对比 CHARACTER_MAXIMUM_LENGTH(字符数)与 CHARACTER_OCTET_LENGTH(字节数),后者才是行大小估算实际吃进去的量。前缀索引长度看 SUB_PART:

SELECT INDEX_NAME, COLUMN_NAME, SUB_PART, NON_UNIQUE
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'app' AND TABLE_NAME = 'orders';

SUB_PART 为 NULL 表示整列索引,非 NULL 则是前缀长度——后者正是 9.7.0 修复中估算变精确的部分,也是最容易踩线的位置。

临时处理路径

确认是校验口径问题而非真实越界后,有两条路:

显式切换算法。 对 ALTER TABLE 指定 ALGORITHM=INPLACE 或 ALGORITHM=COPY,避开 INSTANT 的严格计算。代价要算清楚:INPLACE 通常需要重建表,期间仍可并发 DML,但会占用额外磁盘和 I/O;COPY 走整表拷贝,执行期间阻塞 DML,大表上等于一次停机窗口。用之前先确认表的体量和可接受的锁表时长。

升级到 9.7.4。 如果问题出在 CREATE TABLE 或普通 ALTER TABLE 被误拒,升到 9.7.4 是最省事的做法——多数 DDL 已恢复旧行为。只有 INSTANT 路径依旧严格,需要单独评估。

两条路不冲突:可以先在 9.7.4 上确认普通 DDL 恢复正常,再针对仍走 INSTANT 的变更逐个判断是否需要显式指定算法。

复制全文 生成海报 MySQL DDL 升级 排障

推荐文章

程序员茄子在线接单