能,但仅限于严格满足六项条件:InnoDB引擎、末尾添加、字面量/NULL默认值、Dynamic行格式、无全文索引、单DDL操作;缺一则退化为INPLACE或COPY。

INSTANT算法在MySQL 8.0中真的能秒加字段吗?
能,但仅限于特定条件。INSTANT是MySQL 8.0.12引入的ALTER TABLE算法,它不重写表数据、不锁表(只在DDL元数据阶段短暂加MDL写锁),因此对大表新增列几乎无感知——前提是新增的是NULL列,且不指定DEFAULT值或指定DEFAULT NULL。一旦带非NULL默认值(如DEFAULT 'abc'),MySQL会自动退化为COPY或INPLACE,耗时可能达小时级。
哪些ALTER COLUMN操作会触发INSTANT?
INSTANT只适用于极简的列添加,且受严格限制。以下操作才可能走INSTANT:
- 新增
NULL列,且显式声明DEFAULT NULL(或省略DEFAULT):ADD COLUMN c1 INT NULL - 新增列位置在末尾(不能用
AFTER或FIRST指定位置) - 不涉及全文索引、空间索引、生成列、JSON列、主键/唯一约束变更
- 表引擎必须是
InnoDB,且未启用innodb_file_per_table=OFF - 不能在含有
ROW_FORMAT=COMPRESSED或KEY_BLOCK_SIZE的表上使用
反例:ADD COLUMN c1 VARCHAR(10) NOT NULL DEFAULT 'x' → 强制退化为INPLACE;ADD COLUMN c1 INT AFTER id → 直接报错ER_ALTER_OPERATION_NOT_SUPPORTED。
如何验证ALTER是否真的走了INSTANT?
执行完ALTER TABLE后,查INFORMATION_SCHEMA.INNODB_TABLES或直接看SHOW PROFILE不够直观。最可靠方式是开启performance_schema并捕获DDL事件:
SELECT EVENT_NAME, WORK_COMPLETED, WORK_ESTIMATED FROM performance_schema.events_stages_history_long WHERE EVENT_NAME LIKE '%alter%instant%' ORDER BY TIMER_START DESC LIMIT 1;
更简单的方法是检查执行时间与表大小是否脱钩:对1TB表执行ADD COLUMN x INT NULL,若耗时SHOW PROCESSLIST,若状态长期卡在altering table,说明没走INSTANT。
为什么加了DEFAULT值就失效?
因为INSTANT的本质是“只改数据字典,不在每行物理记录里写默认值”。当查询旧数据时,MySQL在server层动态补DEFAULT;但如果指定了非NULL默认值(如DEFAULT 42),旧记录读取时无法区分“该字段尚未存在”和“该字段值就是42”,语义冲突。所以MySQL强制要求:带非NULL默认值的列,必须把值真正写入每一行——这就绕不开全表扫描和重写。
绕过办法只有两个:
① 先用INSTANT加NULL列:ADD COLUMN c1 INT NULL;
② 再用后台批处理更新值(配合WHERE PK BETWEEN ? AND ?分片);
③ 最后ALTER COLUMN c1 SET DEFAULT 42(这个SET DEFAULT本身是INSTANT)。
注意:MODIFY COLUMN或CHANGE COLUMN永远不支持INSTANT,哪怕只是改个注释。


















