1. 索引创建背后的锁机制真相
第一次在MySQL里添加索引看到"Processing"状态时,我下意识地停下了所有线上操作——毕竟按照传统认知,DDL操作应该会锁表不是吗?但实际监控发现应用读写完全不受影响。这个反直觉的现象促使我深入研究了InnoDB的索引创建机制,发现从MySQL 5.6开始,官方就提供了"Online DDL"这项颠覆性的能力。
1.1 Online DDL的技术实现
传统DDL操作需要获取元数据锁(MDL)的排他锁,这会导致阻塞所有读写请求。而Online DDL通过三个关键阶段实现无锁化:
-
初始化阶段(<100ms)
- 短暂获取MDL锁,检查表结构
- 创建临时日志表记录DML变更(row log)
- 释放MDL锁
-
执行阶段(耗时主要在此)
- 在InnoDB内部创建空B+树结构
- 增量填充索引数据(使用Change Buffer优化)
- 应用实时将DML变更写入row log
-
提交阶段(<1s)
- 短暂获取MDL锁
- 应用row log中的变更
- 切换新索引生效
实测在800万行的用户表上添加复合索引,整个过程耗时2分17秒,期间QPS波动小于3%。这种设计巧妙地将锁冲突窗口从整个操作过程压缩到毫秒级。
关键提示:Online DDL需要满足两个条件——使用InnoDB引擎且
innodb_online_alter_log_max_size参数足够大(默认128MB)
1.2 索引类型与锁的关系
不是所有索引创建都能免锁,具体行为取决于索引类型:
| 索引类型 | 锁级别 | 是否阻塞DML | 适用版本 |
|---|---|---|---|
| PRIMARY KEY | 表级排他锁 | 是 | 所有版本 |
| UNIQUE索引 | 行级意向锁 | 部分阻塞 | ≥5.6 |
| 普通二级索引 | 无锁 | 否 | ≥5.6 |
