执行ALTER TABLE添加索引是否修改表结构、锁表并阻塞其他事务?
问题1:基础问题确认
执行ALTER TABLE操作添加索引属于修改表结构的操作。
所有通过ALTER TABLE触发的、涉及表字段、索引、约束、存储引擎、字符集等表元信息变更的操作都属于DDL(数据定义语言)范畴,核心就是修改表的结构定义,和INSERT/UPDATE/DELETE这类修改表内行数据的DML操作有本质区别。
问题2:场景问题验证
这个场景的结果和MySQL版本、事务操作顺序直接相关,不存在统一的是或否结论,分情况说明:
加索引操作是否会加表锁
- MySQL 5.5及更早的历史版本中,添加二级索引的DDL操作会全程持有排他表锁,整个执行期间表无法执行任何写入、修改操作,查询效率也会受影响。
- MySQL 5.6及之后版本支持Online DDL特性,默认情况下添加普通二级索引会采用
INPLACE执行算法、NONE锁策略:索引构建的核心执行阶段不会加阻塞读写的表锁,仅在DDL启动的元数据检查阶段、执行完成后的元数据提交阶段,会短暂申请MDL(元数据锁)写锁,两个阶段持锁时间极短,正常业务几乎感知不到。
会话B的行更新操作是否会被阻塞
分两种最常见的场景:
- 场景1:会话A开启事务后,直接执行
alter table stu add index idx_name(name);,执行DDL前没有对stu表做过任何读写操作
正常Online DDL执行的核心阶段不会阻塞会话B的行更新,B的更新语句可以正常执行。仅在A的DDL进入最后元数据提交的短暂窗口时,会等待B上未提交的事务释放MDL读锁后完成变更,这个等待如果超过lock_wait_timeout参数设置的阈值,DDL会直接报错回滚,不会长期卡住业务请求。 - 场景2:会话A开启事务后,在执行加索引语句前,已经对
stu表做过任意查询/修改操作(比如提前执行过SELECT * FROM stu LIMIT 1)
会话A的未提交事务会长期持有stu表的MDL读锁,后续执行DDL申请MDL写锁时会进入锁等待队列;此时会话B的行更新需要申请MDL读锁,会被等待队列中优先级更高的MDL写锁阻塞,直接表现就是B的SQL卡住,直到A提交/回滚事务释放MDL锁、DDL执行完成,或者等待超时后报错。
注意:MDL锁是MySQL服务层实现的元数据锁,和InnoDB引擎层面的行锁、表锁不是同一套机制,Online DDL不阻塞DML的特性,绕不开MDL锁的优先级等待规则,这也是线上环境直接执行加索引操作容易引发大面积锁阻塞的核心原因。
内容的提问来源于stack exchange,提问作者aqshing
相关产品推荐
相关产品推荐

