algorithm=inplace不等于无锁,仅避免全表拷贝;它在准备阶段持mdl共享锁,执行阶段通常不升级锁(但add column不满足instant时会短暂升级为排他锁),提交阶段必持极短mdl排他锁更新数据字典。

ALGORITHM=INPLACE 并不等于“完全不加锁”
不是。它只是避免了全表拷贝(COPY),但依然会在关键阶段获取元数据锁(MDL)——尤其是 LOCK=NONE 时,只在提交元数据变更的瞬间加一个极短的 MDL 排他锁;而 LOCK=SHARED 或未显式指定时,则可能在整个 DDL 执行期间持有共享锁,阻塞写入。
哪些阶段会加锁?加什么锁?
整个过程分三段,锁行为差异很大:
- 准备阶段:获取 MDL 共享锁(允许读,阻塞其他 DDL)
- 执行阶段:
ALGORITHM=INPLACE下多数操作不升级锁,DML 可继续;但像ADD COLUMN若不满足INSTANT条件,仍需重写行格式,此时会短暂升级为 MDL 排他锁 - 提交阶段:必须获取 MDL 排他锁,重写数据字典、应用 row-log;哪怕
LOCK=NONE,这一步也逃不掉——只是持续时间极短(毫秒级)
为什么你看到“没报错”就以为没锁?
常见误判来源:
- 只观察命令是否返回成功,没监控业务写入是否卡住——
TRX_STATE长期RUNNING不代表没问题,得看对应线程是否还在处理业务请求 - 误把
LOCK=DEFAULT当成安全选项:它可能悄悄退化为LOCK=SHARED,写操作被阻塞,但 SELECT 看不出异常 - 忽略长事务影响:只要存在未提交的事务(哪怕只是
SELECT),LOCK=NONE就可能直接失败,MySQL 不会降级,而是报错LOCK=NONE is not supported
INSTANT 算法是唯一接近“无感”的例外
MySQL 8.0.12+ 支持 ALGORITHM=INSTANT,仅修改数据字典,连 row-log 都不生成。但它有硬限制:
- 只能用于
ADD COLUMN(且不能是FIRST,不能含NOT NULL+ 默认值以外的约束) - 不能用于
MODIFY COLUMN、DROP COLUMN、索引变更等任何涉及行数据重排的操作 - 即使语法合法,执行前也必须查
information_schema.INNODB_TRX和innodb_ddl_log确认是否真走 INSTANT 路径
真正“完全不加锁”的场景几乎不存在——哪怕 INSTANT,也要抢一次 MDL 写锁。关键是锁的粒度和持续时间,而不是有没有锁。











