INSTANT算法仅在满足六项硬性条件时生效,否则静默降级为INPLACE或COPY;条件包括:末尾ADD COLUMN、列允许NULL且默认值为DEFAULT NULL或省略、InnoDB引擎且innodb_file_per_table=ON、行格式为DYNAMIC、无全文/空间索引及生成列/JSON列、单条ALTER语句。

能快,但“INSTANT”不是万能开关;不满足六项硬性条件时,它会静默退化为INPLACE甚至COPY,锁表时间可能从毫秒跳到小时级。
INSTANT算法真正生效的六个必要条件
INSTANT只在极窄路径下触发,缺一不可,且MySQL不会报错,只会降级执行:
-
ADD COLUMN必须加在列末尾,不能用AFTER或FIRST指定位置 - 列定义必须允许
NULL,且默认值只能是DEFAULT NULL或完全省略(DEFAULT 'x'或NOT NULL直接禁用 INSTANT) - 表引擎必须是
InnoDB,且innodb_file_per_table=ON(默认开启,但需确认) - 行格式必须是
DYNAMIC(COMPACT、REDUNDANT、COMPRESSED均不支持) - 表不能含全文索引、空间索引、生成列、JSON列、主键/唯一约束变更
- 必须是单条
ALTER TABLE语句,不能和其它 DDL 合并在一条命令里
为什么加了 DEFAULT 就失效?
INSTANT 的本质是只改数据字典,不在物理记录里写值。当查询旧行时,MySQL 在 server 层动态补 DEFAULT;但如果指定了非 NULL 默认值(如 DEFAULT 100),旧记录无法区分“字段尚未存在”和“字段值就是 100”,语义冲突。所以 MySQL 强制要求:所有已有行都必须真实写入该值——这就绕不开全表扫描与重写。
绕过方法只有两个:
- 先走 INSTANT 加
NULL列:ADD COLUMN c1 INT NULL - 再用后台批处理更新:
UPDATE t SET c1 = 100 WHERE id BETWEEN ? AND ?,配合LIMIT分片执行
如何验证是否真走了 INSTANT?
别信执行时间短——小表即使 COPY 也很快。关键看行为是否与表大小脱钩:
- 对 1TB 表执行
ADD COLUMN x BIGINT NULL,若耗时仍稳定在 - 执行后立刻查
SHOW PROCESSLIST,状态不应长期卡在altering table - 更可靠方式:开
performance_schema捕获事件:SELECT EVENT_NAME, WORK_COMPLETED FROM performance_schema.events_stages_history_long WHERE EVENT_NAME LIKE '%alter%instant%';若无结果,说明没走 INSTANT
INSTANT 不可用时的替代方案选择
一旦 INSTANT 被绕过,就得面对实际 I/O 和锁竞争。此时选型取决于你的容忍底线:
- 业务可接受秒级元数据锁(MDL)阻塞?用原生
ALGORITHM=INPLACE, LOCK=NONE(注意:仍需双倍磁盘空间,且主从延迟风险未消除) - 表有主键、无外键级联、能装 Percona Toolkit?用
pt-online-schema-change,它通过触发器+影子表规避长锁,但切换瞬间仍有短暂 MDL - 不允许任何写入中断、且能停服?复制表法最可控:
CREATE TABLE t_new LIKE t→ALTER TABLE t_new ADD COLUMN ...→INSERT INTO t_new SELECT *, NULL FROM t→RENAME TABLE t TO t_bak, t_new TO t
INSTANT 看似魔法,实则是把复杂性压进了 metadata 层;真正容易被忽略的,是它对“列定义语义”的严苛限制——哪怕只多一个 NOT NULL,就足以让整套优化彻底失效。


















