登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL INSTANT DDL 不支持时怎么判断回退算法

来源:17golang原创

时间:2026-10-04 13:54:22 333浏览 收藏

我第一次把 ALGORITHM=INSTANT 写进生产变更脚本时,最容易误解的一点是:如果表不支持 INSTANT,MySQL 会不会悄悄降级成 INPLACE?答案是不会。显式指定 ALGORITHM=INSTANT 就是一条执行护栏,不支持时语句报错并停止;只有省略 ALGORITHM,或者写 ALGORITHM=DEFAULT,MySQL 才会在可用能力中选择 INSTANT,不能用时再选择 INPLACE,INPLACE 也不支持时才使用 COPY。

因此,生产环境里判断“回退算法”的重点不是猜服务器最终会选什么,而是先判断这次 DDL 的最低可接受算法,然后用显式 ALGORITHM 与 LOCK 把不可接受的重建或阻塞挡在执行前。官方说明入口:https://dev.mysql.com/doc/refman/8.4/en/alter-table.html

判断结论
  • 显式 ALGORITHM=INSTANT 不支持就报错,不会自动回退。
  • 省略算法或使用 DEFAULT 才允许 MySQL 按 INSTANT、INPLACE、COPY 的支持能力自动选择。
  • 生产变更不建议依赖静默回退;先按操作类型和表属性判断,再显式批准 INPLACE 或 COPY。

先分清显式失败和默认回退

MySQL 8.4 把 ALTER TABLE 的执行算法分为三类。INSTANT 只修改数据字典中的元数据,表数据不受影响;INPLACE 避免使用逐行复制到新表的 COPY 方式,但某些操作仍会在原地重建表;COPY 则创建表副本并逐行复制数据,执行期间不能并发写入。

写法不支持 INSTANT 时适合场景
ALGORITHM=INSTANT直接报错,语句不自动改用其他算法只接受元数据变更,希望阻止意外重建
省略 ALGORITHM尝试可支持的 INPLACE,再不支持时使用 COPY能够接受服务器自动选择,且已有充分变更窗口
ALGORITHM=DEFAULT与省略算法相同显式表达“允许服务器选择”
MySQL DDL 显式 INSTANT 约束、DEFAULT 选择与三种算法能力的关系
图1:显式算法约束与默认算法选择的静态关系图。它是说明图,不是数据库运行截图。

这一区别很重要。把 ALGORITHM 省略掉,并不是“先试 INSTANT,失败后让我确认”,而是授权服务器继续寻找可执行算法。大表上真正危险的情况,往往不是 DDL 失败,而是它成功地落到了比预期更重的算法。

把算法写成生产变更护栏

我更倾向于把 DDL 分成两次评审,而不是把所有回退可能都交给默认值。第一份语句只允许 INSTANT;若官方能力表和当前表属性表明它不可能成功,就直接进入 INPLACE 或 COPY 的专项评审,而不是在线上执行默认算法。

-- 只允许元数据级变更;不支持时立即报错,不自动重建表
ALTER TABLE orders
  ADD COLUMN review_flag TINYINT NOT NULL DEFAULT 0,
  ALGORITHM=INSTANT;

INSTANT 操作只能使用 LOCK=DEFAULT。不要给它附加 LOCK=NONE,因为其他 LOCK 参数对 INSTANT 不适用。INSTANT 仍可能在执行阶段短暂获取排他元数据锁,所以“瞬时”并不等于完全不等待:如果前面有长事务持有相关元数据锁,DDL 仍可能排队。

如果已经判断需要 INPLACE,并且业务要求继续读写,可以把并发要求也写进语句。LOCK=NONE 不受支持时会报错,这比默默接受更强的锁级别更适合作为生产保护。

-- 添加普通二级索引不支持 INSTANT,但 InnoDB 通常支持 INPLACE
-- LOCK=NONE 表示必须允许并发读写,否则让语句失败
ALTER TABLE orders
  ADD INDEX idx_created_status (created_at, status),
  ALGORITHM=INPLACE,
  LOCK=NONE;

这里的“报错”不是坏结果,而是护栏按预期工作。它告诉发布系统:当前操作、表结构或锁要求与计划不一致,需要重新评审,而不是继续消耗生产窗口。

从操作类型判断候选算法

判断回退算法时,第一层先看 DDL 动作本身。官方 Online DDL 表已经给出每类操作是否支持 INSTANT、INPLACE、是否重建表以及是否允许并发 DML。先用它缩小范围,通常比从报错文本猜更可靠。

典型操作INSTANT下一候选生产判断
添加普通列支持,但有表属性和行版本限制INPLACEINPLACE 添加列会重建表,必须重新评估时间与空间
添加普通二级索引不支持INPLACE通常允许并发 DML,可用 LOCK=NONE 作为要求
修改列数据类型不支持COPY属于重型变更,应准备复制空间和写阻塞窗口
修改列默认值支持INPLACE通常是元数据修改,但仍要关注元数据锁等待
重排列顺序不支持INPLACE会重建表,不应只因语法简单就当作轻量变更

“INPLACE”这个名称也容易给人错误安全感。它表示避免 COPY 算法的逐行复制模型,不保证没有表重建,也不保证整个过程都不占空间。比如用 INPLACE 添加列时,MySQL 8.4 官方说明表会被重建;只是执行机制和 COPY 不同。

当动作本身就不支持 INSTANT,例如添加普通二级索引,不需要先在线上执行一次 INSTANT 来获得错误。直接从能力表得出 INPLACE 候选,再结合 LOCK 与空间条件评审即可。

检查会让 INSTANT 失效的表属性

第二层看当前表。即使“添加列”在 MySQL 8.4 支持 INSTANT,具体表仍可能因为行格式、索引或内部行版本而不符合条件。上线前至少应保存完整表定义,并查询 InnoDB 元数据。

-- 保存完整表定义,核对存储引擎、ROW_FORMAT、索引和列属性
SHOW CREATE TABLE app_db.orders;

-- 查看表级引擎和行格式,避免只凭建表脚本判断线上现状
SELECT TABLE_SCHEMA, TABLE_NAME, ENGINE, ROW_FORMAT
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'app_db'
  AND TABLE_NAME = 'orders';

-- 查看 INSTANT 加列/删列累计的内部行版本数量
SELECT NAME, TOTAL_ROW_VERSIONS
FROM INFORMATION_SCHEMA.INNODB_TABLES
WHERE NAME = 'app_db/orders';
MySQL INSTANT DDL 与存储引擎、行格式、全文索引、行版本、算法和锁约束的静态关系
图2:INSTANT DDL 预检要素的静态边界图。它是说明图,不代表某次真实执行结果。

以添加或删除列为例,MySQL 8.4 文档列出的常见限制包括:

  • ROW_FORMAT=COMPRESSED 的表不能用 INSTANT 添加或删除列。
  • 含 FULLTEXT 索引的表不能用 INSTANT 添加或删除列。
  • 位于数据字典表空间的表和临时表不适用;临时表只支持 COPY。
  • 一次 ALTER 中混入不支持 INSTANT 的其他动作,会让整条组合变更不能使用 INSTANT。
  • 添加列后若最大可能行大小超过限制,服务器会拒绝 INSTANT,并提示尝试 INPLACE/COPY。
  • MySQL 8.4 表的内部总列数上限与行版本上限也会导致 INSTANT 被拒绝;反复瞬时加列、删列会累计 TOTAL_ROW_VERSIONS。

错误信息可以作为当前失败原因的补充,但不能代替预检。特别是组合 ALTER,先拆开每个动作判断是否支持 INSTANT;如果其中一个动作需要重建,整条语句的风险边界就已经改变。

形成可执行的回退决策

INSTANT 失败后,我会先问三个问题,而不是直接把算法改成 DEFAULT。

  1. 操作本身是否支持 INPLACE?如果官方能力表明确为否,就不要试探,直接按 COPY 级别评审。
  2. INPLACE 是否会重建表?会重建时,要按表数据量、临时空间、I/O 和复制延迟重新安排窗口。
  3. 并发要求能否被强制?需要持续读写时,使用支持的 LOCK=NONE;不支持就失败,而不是接受更强锁。

可以把决策写成下面这张速查表:

判断结果建议语句策略需要额外批准的风险
INSTANT 支持且只接受元数据变更显式 ALGORITHM=INSTANT元数据锁等待、组合动作限制
INSTANT 不支持,INPLACE 支持且允许所需并发显式 ALGORITHM=INPLACE,必要时加 LOCK=NONE是否重建、临时空间、I/O、复制延迟
INPLACE 不支持显式 ALGORITHM=COPY完整副本空间、写阻塞、切换锁和回滚窗口
无法确认表属性或窗口不足停止发布,不使用 DEFAULT 猜测补齐预检、演练和容量估算
-- 修改列数据类型不支持 INSTANT 或 INPLACE 时,只能显式接受 COPY
-- 该操作会复制数据并阻塞并发写入,必须在批准的维护窗口执行
ALTER TABLE orders
  MODIFY COLUMN external_ref VARCHAR(128) NOT NULL,
  ALGORITHM=COPY;

不要把 INSTANT → INPLACE → COPY 写成客户端自动重试链。第一次失败可能来自元数据锁、行大小、磁盘、权限或语法,不一定只是算法不支持。自动换算法会把一个可控失败升级成高成本执行。更稳妥的是让每一级算法对应独立的风险审批和发布窗口。

上线前后的发布检查

算法判断只是生产 DDL 的一部分。真正上线前,我会把检查项分成环境、权限、并发、空间、审计和回滚六组:

  • 环境:记录 MySQL 版本、存储引擎、表大小、行格式、分区、索引和 TOTAL_ROW_VERSIONS。
  • 权限:使用专用变更账号,授予完成本次 ALTER 所需的最小权限,不在脚本中保存口令。
  • 并发:检查长事务和元数据锁等待,设置符合发布窗口的会话级锁等待策略。
  • 空间:INPLACE 重建和 COPY 都可能需要显著额外空间;共享表空间的空间回收特性也要单独考虑。
  • 审计:保存最终 SQL、算法、锁要求、开始结束时间、错误码和变更单号,不把成功耗时当作下一张表的保证。
  • 回滚:结构回滚同样可能是重型 DDL。先准备兼容旧结构的应用回退方案,避免把“再改回去”当成即时撤销。

如果需要在执行期间观察 INPLACE 变更,可以使用 Performance Schema 的 ALTER TABLE 阶段事件;但那是运行监控,不是算法预判。预判仍应来自官方支持矩阵、当前表定义和显式算法护栏。

几个容易混淆的问题

MySQL 会在 INSTANT 报错后自动改用 INPLACE 吗?

显式写了 ALGORITHM=INSTANT 时不会。语句会报错。只有省略算法或使用 ALGORITHM=DEFAULT,服务器才会选择受支持的算法。

可以用 EXPLAIN ALTER TABLE 预览算法吗?

MySQL 8.4 的 EXPLAIN 可解释 SELECT、TABLE、DELETE、INSERT、REPLACE 和 UPDATE,不包含 ALTER TABLE。不要把其他数据库或工具的预检语法直接套到 MySQL。对生产 DDL,应使用官方 Online DDL 支持表、表元数据和显式算法限制来判断。

INPLACE 就一定不重建表吗?

不一定。INPLACE 不等于“只改元数据”。例如使用 INPLACE 添加列时会重建表;是否重建要查看具体操作的 Online DDL 支持说明。

INSTANT 为什么还会等锁?

INSTANT 不改表数据,但执行阶段仍可能短暂获取排他元数据锁。前方有长事务或持锁会话时,它仍可能等待,因此上线前要检查元数据锁和长事务。

什么时候可以使用 DEFAULT?

只有当变更窗口、空间和并发控制已经按最重可能算法准备好,而且团队明确接受服务器自动选择时才适合。多数大表生产变更更适合显式算法,因为失败通常比意外落到 COPY 更容易控制。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>