INSTANT加列快在仅修改元数据:只更新mysql.columns、递增TOTAL_ROW_VERSIONS、标记行版本,不触碰数据页;旧数据读取时动态补默认值,新数据写入才存值。

能秒加字段,但前提是别踩到 MySQL 的“元数据边界”——INSTANT 不是语法开关,而是对操作是否动了真实数据的实时判断。
INSTANT 加列到底快在哪?关键看它动没动数据页
INSTANT 的毫秒级响应,来自它完全不碰用户数据页:只往 mysql.columns 插一条记录、更新表的 TOTAL_ROW_VERSIONS、在行头加个版本标记。旧数据读出来时,InnoDB 动态补默认值;新数据写入时,才真正存新增列的值。
一旦你要求它改已有数据(比如 MODIFY COLUMN、ALTER COLUMN SET DEFAULT、把 NOT NULL 加到已有列上),它立刻退化为 INPLACE,开始扫描并重写每一行——锁表时间从毫秒跳到分钟级。
-
ADD COLUMN c INT DEFAULT 0→ INSTANT(只改字典) -
ALTER COLUMN c SET DEFAULT 1→ INPLACE(要回填所有旧行) -
MODIFY COLUMN c BIGINT NOT NULL→ INPLACE 或 COPY(改类型+约束=重写行结构)
ALGORITHM=INSTANT 必须显式写,否则你根本不知道它悄悄降级了
MySQL 默认会“先试 INSTANT,不行就切 INPLACE,再不行就 COPY”,全程静默。你看到 Query OK,实际可能刚锁表 8 分钟——而业务已经报警了。
显式指定 ALGORITHM=INSTANT 后,不满足条件直接报错,错误信息明确指向根因:
ERROR 1845 (0A000): ALGORITHM=INSTANT is not supported for this operation. Try ALGORITHM=COPY/INPLACE.
这时你能立刻排查:
- 是不是用了
AFTER col_name却还在 8.0.28 或更早版本? - 表是不是
ROW_FORMAT=COMPRESSED? - 有没有全文索引(
FULLTEXT)或空间索引? - 新增字段是不是
PRIMARY KEY、AUTO_INCREMENT或STORED GENERATED COLUMN?
8.0.12 和 8.0.29 是两个关键分水岭,查版本不能靠猜
别信“MySQL 8.0 就支持 INSTANT”这种模糊说法。版本差异直接决定语法能不能用:
SELECT VERSION(); 是执行前第一件事。
- 低于
8.0.12:INSTANT 直接报错ERROR 1845,不兼容 -
8.0.12–8.0.28:只支持末尾加列,AFTER user_id会自动 fallback 到 INPLACE,耗时不可控 -
8.0.29+:支持AFTER/FIRST定位、单语句多列增删、DROP COLUMN,才算真正可用
顺带一提:LOCK=NONE 和 ALGORITHM=INSTANT 不能共存,会报 HY000: Incorrect usage of ALGORITHM=INSTANT and LOCK=NONE ——INSTANT 本身就不需要额外锁控制。
行版本数超 64 会彻底堵死 INSTANT,重建表是唯一解
每次 ADD 或 DROP COLUMN 都会让表的 TOTAL_ROW_VERSIONS +1,上限硬编码为 64(MySQL 9.1 才升到 255)。超限后连最简单的加列都会被拒:
ERROR 4092 (HY000): Maximum row versions reached for table test/orders. No more columns can be added or dropped instantly.
这时候没有绕过办法。必须用 ALGORITHM=COPY 或 ALGORITHM=INPLACE 重建表(比如 OPTIMIZE TABLE orders),才能把 TOTAL_ROW_VERSIONS 重置为 0。
这个限制容易被忽略:它不随表数据量变化,只和你“改过多少次结构”有关。高频迭代的配置表、日志表,比大订单表更容易先撞墙。


















