MySQL 9.7.4 回退了收紧的建表校验,但 INSTANT DDL 仍在用严格行大小估算
信源:MySQL 9.7 Release Notes — Changes in MySQL 9.7.4 (2026-10-20)
这版有四处直接影响升级动作:InnoDB 行大小估算导致的 DDL 校验回退、四段版本号接口、EXCHANGE PARTITION 改双向校验,以及 MeCab 全文解析和 Group Replication 各一条修复。
InnoDB 行大小估算:大多数 DDL 回退到旧校验,INSTANT 例外
InnoDB: A previous InnoDB deadlock fix made row-size estimates more accurate for B-tree operations, but also made CREATE TABLE and ALTER TABLE validation stricter. As a result, some table definitions accepted by earlier MySQL LTS releases were unexpectedly rejected or produced warnings, disrupting existing applications. As of this release, the legacy validation behavior is preserved for most DDL operations while retaining the accurate estimate where it is needed to prevent B-tree deadlocks. ALTER TABLE ... ALGORITHM=INSTANT continues to use the stricter calculation to safely handle large default values.
Bug #120323, Bug #39249507。贡献者来自 Percona(Paweł Olchawa)和 Amazon(Meng-Hsiu Chiang)。
9.7 早期小版本里,一个为修死锁而加的「行大小估算更准」逻辑,副作用是把 DDL 校验也收紧了:8.0/8.4 上能建出来的表,升到 9.7.x 后建表被拒或被 warning。9.7.4 的处理是分开对待——大多数 DDL 恢复旧校验,ALTER TABLE ... ALGORITHM=INSTANT 仍走严格算法,因为大默认值走 INSTANT 需要这个计算来保证安全。
所以用 gh-ost、pt-osc 或自研 online DDL 脚本时,凡是「INSTANT 加带大默认值的列」,行为与 8.0 不同。先在生产副本上 dry run。
验证方式是把线上真实 DDL 在两套版本上跑一遍:
-- 1) 在 8.0/8.4 上执行线上真实的建表语句,记下是否通过、有无 warning
-- 2) 在 9.7.4 上执行同一份 DDL,行为应与 8.0/8.4 一致
SHOW WARNINGS;
-- 3) INSTANT 加列仍走严格算法,单独验证这一条路径
ALTER TABLE t_row_est
ADD COLUMN big_default VARCHAR(2000) NOT NULL DEFAULT 'x',
ALGORITHM=INSTANT;
版本号变成四段,但 VERSION() 还是三段
MySQL Server now supports a four-part release identity in the form MAJOR.MINOR.PATCH.UPDATE, with an empty update component represented as zero. The complete version is available through VERSION_WITH_UPDATE(), the read-only global version_with_update variable, mysqld --version-with-update, and new client-library APIs ... Existing interfaces, including VERSION(), version, the classic handshake, numeric version IDs, and existing C APIs, retain three-part compatibility semantics. mysql_upgrade_history records exact update transitions without changing upgrade compatibility decisions.
Bug #40013285, WL #17318。
同一个 PATCH 里可以再出一个 UPDATE 修订。取完整版本号的几个入口:
SELECT VERSION_WITH_UPDATE();
SELECT @@global.version_with_update;
mysqld --version-with-update
关键在于 VERSION() 仍返回三段。这意味着字符串 9.7.4 无法区分 9.7.4 和 9.7.4 的 update 修订。做版本比较的脚本、连接池/ORM 的能力探测、监控采集,如果只解析 VERSION(),会漏掉 update 级差异。mysql_upgrade_history 记录精确的 update 变迁,但不参与升级兼容性判断。
update 位是留给公开社区版本还是厂商补丁,官方未作说明,需自行核对。接口已经存在,@@version 不再是唯一事实来源。
EXCHANGE PARTITION 改成双向校验
ALTER TABLE ... EXCHANGE PARTITION could move rows that violated the destination table's CHECK constraints or exchange tables whose generated columns used different expressions. Rows are now checked in both directions, including when WITHOUT VALIDATION skips partition-bound checks, and mismatched generated-column definitions are rejected.
Bug #120206, Bug #39634208。典型报错:
ERROR 3819 (HY000): Check constraint 't_swap_chk_1' is violated.
用分区表做归档(把旧分区 exchange 到临时表再导出)时,以前 WITHOUT VALIDATION 只跳过分区边界检查,CHECK 约束和生成列表达式都不校验,坏数据能混进去。现在两个方向都查。
复现 CHECK 这一条:
CREATE TABLE t_swap (
id INT NOT NULL,
v INT NOT NULL
) ENGINE=InnoDB
PARTITION BY RANGE (id) (
PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
-- 历史坏数据,落进 p0
INSERT INTO t_swap VALUES (-1, -1);
-- 目标表不能带分区定义
CREATE TABLE t_swap_new (
id INT NOT NULL,
v INT NOT NULL,
CONSTRAINT t_swap_chk_1 CHECK (v > 0)
) ENGINE=InnoDB;
ALTER TABLE t_swap EXCHANGE PARTITION p0 WITH TABLE t_swap_new WITHOUT VALIDATION;
-- 9.7.4: ERROR 3819 (HY000): Check constraint 't_swap_chk_1' is violated.
生成列表达式不一致同样会被拒:
CREATE TABLE t_swap_g (
id INT NOT NULL,
a INT NOT NULL,
g INT GENERATED ALWAYS AS (a + 1) STORED
) ENGINE=InnoDB
PARTITION BY RANGE (id) (
PARTITION p0 VALUES LESS THAN (100),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
CREATE TABLE t_swap_g_new (
id INT NOT NULL,
a INT NOT NULL,
g INT GENERATED ALWAYS AS (a + 2) STORED
);
ALTER TABLE t_swap_g EXCHANGE PARTITION p0 WITH TABLE t_swap_g_new;
另外两条与线上相关的修复
MeCab 全文解析失败会报警告,不再静默漏行
外部 MeCab 解析器在延迟 FULLTEXT 分词阶段失败时,基表行可能在缺少完整 token postings 的情况下提交,导致搜索漏行。现在解析失败会给客户端 warning(autocommit 语句同样返回),错误形如:
Mecab: parse() failed: too long sentence..
Bug #39838534。排查「某些行搜不到」时先看 warning,不要直接重建索引。
SHOW WARNINGS;
这条依赖外部 MeCab 解析器插件,社区版默认不带,验证前先确认 WITH PARSER mecab 的表能建起来。
Group Replication 网络恢复后的重连循环
网络分区恢复后,组可能丢 quorum 并卡在重连循环里,网络恢复后写入仍被阻塞。修复把连接委派改为单次非阻塞发布尝试,让正常重连逻辑负责重试。错误形如:
MY-013781: Error sending connection delegation command
Bug #39767762。升级后可以用这条确认是否还命中:
grep -i "MY-013781" /var/log/mysql/error.log