INSTANT算法加字段最安全,但需严格满足条件:MySQL≥8.0.12、InnoDB引擎、ROW_FORMAT=Dynamic/Compact、无FULLTEXT索引、单操作且默认值为字面量;不显式指定ALGORITHM=INSTANT将静默降级,不满足则报错ERROR 1845,避免隐性锁表风险。

能安全加,但“安全”不等于“随便写个 ALTER TABLE ADD COLUMN 就行”。真正安全的前提是:你清楚当前表是否满足 INSTANT 条件,且已排除长事务阻塞、行格式不兼容、默认值语义冲突等隐形雷区。
怎么确认你的表能走 INSTANT 算法?
别猜,直接查。INSTANT 不是默认开关,它只在全部条件满足时才生效,漏一条就降级——而降级后仍会成功执行,你根本不会收到警告。
- 先确认 MySQL 版本:
SELECT VERSION();,低于8.0.12直接不支持ALGORITHM=INSTANT - 查表引擎和行格式:
SELECT ENGINE, ROW_FORMAT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';,必须是InnoDB且ROW_FORMAT为Dynamic或Compact(COMPRESSED或REDUNDANT都不行) - 检查有无全文索引:
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table' AND INDEX_TYPE = 'FULLTEXT';,有则 INSTANT 失效 - 确认字段定义不含函数或表达式:
DEFAULT CURRENT_TIMESTAMP、DEFAULT (uuid())、NOT NULL DEFAULT 'x'全部触发降级;只允许DEFAULT NULL、DEFAULT 0、DEFAULT 'a'这类字面量
为什么显式写 ALGORITHM=INSTANT 是硬性要求?
因为不写,MySQL 会“悄悄降级”。比如你加了个 AFTER id,8.0.28 及之前版本会自动 fallback 到 INPLACE,耗时从毫秒跳到几分钟,而你只看到“Query OK”。显式指定后,不满足就立刻报错:
ERROR 1845 (0A000): ALGORITHM=INSTANT is not supported for this operation. Try ALGORITHM=COPY/INPLACE.
这个错误比业务告警来得早得多。它逼你停下来检查:是不是表用了压缩?是不是有全文索引?是不是加在中间了?而不是等监控里 Waiting for table metadata lock 堆成山才反应过来。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
加字段时被卡住,大概率不是算法问题,而是 MDL 被堵了
即使你写了 ALGORITHM=INSTANT, LOCK=NONE,DDL 仍需在开始和结束瞬间获取一次 MDL_EXCLUSIVE 锁。如果此时有个事务只执行了 BEGIN; SELECT ...; 却没 COMMIT,DDL 就会永远排队。
- 查谁在堵:
SELECT THREAD_ID, PROCESSLIST_TIME, PROCESSLIST_INFO FROM performance_schema.threads t JOIN performance_schema.events_statements_current e USING (THREAD_ID) WHERE t.PROCESSLIST_COMMAND = 'Sleep' AND t.PROCESSLIST_TIME > 60; - 别等 DDL 超时重试,优先
KILL那些长时间Sleep的连接 - 预防比抢救重要:应用层避免裸
BEGIN,DBA 层设置合理的wait_timeout(比如 300 秒)
加完怎么验证真走了 INSTANT?
不能只看执行时间短——小表本来就快。关键看它是否与数据量脱钩:
- 对千万行、亿行甚至几十亿行的表,执行耗时都稳定在 SHOW PROCESSLIST 中状态不是
altering table,而是瞬间变成Query OK - 查
performance_schema.events_statements_history,过滤出刚执行的ALTER语句,看ALGORITHM字段是否为INSTANT - 更直接的办法:执行前后跑一次
SELECT COUNT(*) FROM information_schema.INNODB_TABLESPACES_BY_TABLE WHERE TABLE_NAME = 'your_table';,INSTANT 不会产生新表空间,结果应完全一致
最易被忽略的一点:INSTANT 每次增删列都会增加一个行版本(TOTAL_ROW_VERSIONS),上限是 64。超了之后再加列会强制退化为 INPLACE,且无法回退——这时只能重建表重置版本计数。这不是故障,但它是隐藏的“保质期”。










