MySQL 8.0的ADD COLUMN默认“秒级”完成,因其引入Instant Add Column机制,仅修改元数据而不重建表或拷贝数据;该机制要求操作唯一、列追加末尾、默认值为字面量或NULL、表格式为Dynamic、无全文索引等,否则退化为INPLACE或COPY。

MySQL 8.0 的 ADD COLUMN 为什么默认“秒级”完成?
因为 MySQL 8.0 引入了 Instant Add Column(即时加列)机制,只要满足条件,ALTER TABLE ... ADD COLUMN 就不会触发表重建,也不需要拷贝整张表数据。它只修改数据字典(mysql.innodb_table_stats 等元数据表)和表定义(.frm 或数据字典表),物理行格式不变,自然快。
这和 MySQL 5.7 完全不同:5.7 下绝大多数 ADD COLUMN 都会走 ALGORITHM=COPY(即使显式指定 INPLACE,也常被降级),必须重建聚簇索引、重写所有数据页。
哪些 ADD COLUMN 操作能走 Instant?
必须同时满足以下全部条件,否则退化为 INPLACE 或 COPY:
-
ADD COLUMN必须是语句中唯一的操作(不能和DROP COLUMN、RENAME COLUMN、MODIFY COLUMN等混用) - 新增列不能是
FIRST(即不能加到最前面),必须是AFTER xxx或默认追加到末尾 - 新增列不能有
DEFAULT值为表达式(如NOW()、UUID()),但允许DEFAULT NULL或字面量(DEFAULT 'abc'、DEFAULT 42) - 新增列不能是生成列(
GENERATED ALWAYS AS)或全文索引列 - 表必须使用
ROW_FORMAT=Dynamic或Compressed(Compact和Redundant不支持 Instant) - 表不能有全文索引(
FULLTEXT)
执行后可通过 SHOW CREATE TABLE tbl_name 查看是否生效:若输出中包含 ALGORITHM=INSTANT,说明走的是 Instant;若没提或显示 INPLACE,就不是。
为什么有时 ADD COLUMN 还是慢?常见退化场景
Instant 是“默认开启但有条件触发”的特性,很多看似简单的加字段操作实际已悄悄退化:
- 在已有
FULLTEXT索引的表上执行ADD COLUMN→ 强制COPY,哪怕只是加一个TINYINT - 执行
ALTER TABLE t ADD COLUMN c1 INT DEFAULT (id + 1)→ 表达式默认值不支持 Instant,退化为INPLACE(仍需遍历每行计算) - 用
pt-online-schema-change或gh-ost工具改表 → 它们不识别 Instant,一律走影子表逻辑,完全绕过该优化 - MySQL 8.0.12 之前版本对
NOT NULL+ 字面量DEFAULT支持不完整,部分情况会误判为需填充旧数据而拒绝 Instant
验证方式:执行前打开 innodb_monitor_output 或查 information_schema.INNODB_METRICS 中的 dml_rows_inserted,如果加字段期间该计数暴涨,说明正在写新行,已退化。
Instant Add Column 对旧数据行的影响
Instant 不修改现有行记录,而是靠 InnoDB 记录头中的 NULL-bit mask 和 extra bytes 动态解释字段是否存在。新插入的行带新字段值;老行读取时,引擎自动补 DEFAULT 或 NULL —— 这个过程对 SQL 层透明,但有隐含成本:
- 首次读取老行时需做字段映射解析,比纯固定格式略慢(通常可忽略)
- 如果后续执行
UPDATE老行,InnoDB 会把该行“升级”为带新字段的格式(即真正写入默认值),此时产生一次额外的页内重组织 - 无法用
SELECT * FROM t WHERE new_col IS NOT NULL高效过滤老数据(因为老行根本没存这个字段,IS NOT NULL永远为 false)
真正要小心的不是速度,而是语义一致性:加字段后立即用新字段做 WHERE 或 ORDER BY,结果可能不符合直觉,尤其当业务假设“所有行都有该字段”时。


















