mysql中真正支持algorithm=inplace且lock=none的操作包括:添加/删除普通二级索引、末尾添加无约束列、仅修改default值、扩大varchar长度(utf8mb4且未超行限制);其余如改类型、加唯一索引、非末尾加列等均不支持lock=none,会报错或降级为copy算法。

MySQL在线DDL操作卡住,不是“加了ALGORITHM=INPLACE就一定不锁表”,关键得看操作类型、引擎版本、事务状态和锁粒度是否匹配。
哪些ALTER操作真正支持LOCK=NONE?
很多人误以为只要写上ALGORITHM=INPLACE就能无锁,其实MySQL只对极少数变更允许LOCK=NONE(即读写都不阻塞)。在InnoDB + MySQL 8.0环境下,以下操作可安全组合使用:ALGORITHM=INPLACE, LOCK=NONE:
-
ALTER TABLE t ADD INDEX idx_col (col)(普通二级索引) ALTER TABLE t DROP INDEX idx_col-
ALTER TABLE t ADD COLUMN c INT DEFAULT 0(仅限末尾添加,且不指定AFTER或FIRST) -
ALTER TABLE t ALTER COLUMN c SET DEFAULT 1(仅改DEFAULT值,不碰类型、NULL性) -
ALTER TABLE t MODIFY COLUMN c VARCHAR(500)(仅扩大长度,且utf8mb4下未超行限制)
以下操作哪怕写了LOCK=NONE也会直接报错:ERROR 1846 (HY000): ALGORITHM=INPLACE is not supported for this operation 或 LOCK=NONE is not supported:
-
ADD COLUMN指定位置(如AFTER x) -
MODIFY COLUMN或CHANGE COLUMN改数据类型 DROP COLUMN- 任何涉及主键、唯一索引、外键的变更
SHOW PROCESSLIST里看到copy to tmp table说明什么?
这代表MySQL已降级为COPY算法——意味着全量复制、全程排他锁、所有DML被阻塞。此时ALGORITHM=INPLACE没生效,常见诱因有:
- 字段类型变更(如
VARCHAR(255) → VARCHAR(1000)超出页内存储限制) - 加唯一索引(
UNIQUE KEY),即使数据无重复,MySQL也默认走COPY - 表使用MyISAM引擎(不支持INPLACE)
- 存在长事务正在执行
SELECT,持有S MDL锁,导致DDL卡在等待X MDL阶段
注意:即使状态显示Waiting for table metadata lock,也不一定是DDL本身慢,更可能是前面有个未提交的SELECT在“挡路”。
为什么ALGORITHM=INPLACE还卡住不动?
因为INPLACE ≠ 无锁。它只是避免全表拷贝,但依然要获取元数据锁(MDL)。如果此时有活跃事务正读这张表(比如一个没提交的SELECT * FROM t),DDL就会卡在MDL等待队列里,表现为“零CPU、零IO、零日志输出”的假死状态。
- 查阻塞源头:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA = 'db' AND OBJECT_NAME = 't' - 找长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME > 60 - 杀掉阻塞会话:
KILL <processlist_id></processlist_id>(务必确认该会话非核心业务)
别忘了检查磁盘空间——INPLACE虽不复制全表,但重建索引仍需临时空间;若tmpdir所在分区满,也会卡在准备阶段。
大表加字段/改类型时,真没法完全避免锁表?
对,如果操作不满足LOCK=NONE条件(比如必须MODIFY COLUMN),那就得接受锁。此时能做的只有控制影响范围:
- 选低峰期执行,配合
LOCK=SHARED(允许读,阻塞写),比默认LOCK=EXCLUSIVE稍友好 - 用
pt-online-schema-change或gh-ost做影子表切换,但要注意触发器开销或binlog延迟风险 - 提前预热从库,避免主库DDL一完成,从库SQL线程就开始几小时回放
最常被忽略的一点:autocommit=0下随手写的SELECT不提交,比DDL本身更容易让整个表“静默瘫痪”。











