mysql 5.7中add fulltext index、drop primary key、含大字段/重复校验的add unique index等操作必然触发全表锁,因其不支持inplace而强制退化为copy算法并全程持有mdl_exclusive锁。

MySQL 5.7 的 Online DDL 对某些索引修改仍会锁表,根本原因不是“没开 Online”,而是这些操作本身不支持 ALGORITHM=INPLACE 或强制退化为 COPY 算法,且全程必须持有 MDL_EXCLUSIVE 锁。
哪些索引操作在 5.7 中必然触发全表锁
不是所有“加索引”都安全。以下操作在 MySQL 5.7 中基本无法避免锁表,尤其当表上有活跃事务时:
-
ADD FULLTEXT INDEX:5.7 不支持INPLACE创建全文索引,只能走COPY,全程持MDL_EXCLUSIVE -
DROP PRIMARY KEY:必须重建聚簇索引,触发COPY,且隐式要求排他元数据锁 -
ADD UNIQUE INDEX含大字段(如TEXT、BLOB)或存在重复值校验风险时:优化器可能降级为COPY,而非真正INPLACE - 对
ROW_FORMAT=COMPACT表添加二级索引:若页分裂频繁或统计信息不准,也可能回退到COPY
ALGORITHM=INPLACE 和 LOCK=NONE 的真实作用边界
这两个参数不是开关,而是“申请书”——MySQL 会根据操作类型、表结构、引擎状态决定是否批准:
-
ALGORITHM=INPLACE仅表示“尝试跳过临时表”,但像MODIFY COLUMN这类变更列定义的操作,即使加了该参数也会报错ERROR 0A000: ALGORITHM=INPLACE is not supported -
LOCK=NONE在 5.7 中只对极少数操作有效(如末尾ADD COLUMN、普通ADD INDEX),且前提是无长事务、无外键、无全文索引、row_format为DYNAMIC或COMPRESSED - 哪怕
ALGORITHM=INPLACE成功,它也只规避物理重建;元数据变更阶段(打开表、更新数据字典、写 binlog)仍需短暂MDL_EXCLUSIVE,遇未提交的SELECT就卡住
如何提前验证一个索引操作是否真能“在线”
别等上线再看 Waiting for table metadata lock,用组合命令实测:
- 先加
ALGORITHM=INPLACE, LOCK=NONE执行,观察是否报错;报错即说明不支持在线 - 成功执行后,立刻查
EXPLAIN FORMAT=JSON对应的ALTER语句(需开启performance_schema并捕获 DDL 事件),确认"alter_algorithm": "inplace"和"supports_inplace": true - 查
performance_schema.metadata_locks,过滤目标表,看是否有LOCK_DURATION = 'TRANSACTION'的 S 锁长期持有者 - 检查
information_schema.INNODB_TRX中运行超 60 秒的事务,它们是 MDL 阻塞最常见源头
为什么 CREATE INDEX 比 ALTER TABLE ... ADD INDEX 更安全
这是 5.7 中少有的明确差异点:
-
CREATE INDEX idx ON t(col)在多数场景下默认走INPLACE,且LOCK=NONE支持度更高 -
ALTER TABLE t ADD INDEX idx(col)更容易触发隐式约束检查(如外键、分区表逻辑),导致降级 - 二者底层都调用相同 DDL 引擎,但 parser 层对
CREATE INDEX的路径更“干净”,干扰更少
真正危险的从来不是“加索引”这个动作本身,而是你没意识到:只要操作涉及元数据变更,就绕不开 MDL_EXCLUSIVE;而只要有一个未提交的 SELECT,它就会变成一根钉子,把整个 DDL 钉死在原地。











