旧版本 MySQL 在线 DDL 加索引锁表新版本如何避免

文章导读
MySQL 5.6 及以上版本支持 Online DDL,通过显式指定ALGORITHM=INPLACE, LOCK=NONE可在大多数加索引场景避免锁表。若版本低于 5.6 或操作不支持 Online DDL(如修改主键、非空表加全文索引),需使用pt-online-schema-change工具。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

MySQL 5.6 及以上版本支持 Online DDL,通过显式指定ALGORITHM=INPLACE, LOCK=NONE可在大多数加索引场景避免锁表。若版本低于 5.6 或操作不支持 Online DDL(如修改主键、非空表加全文索引),需使用pt-online-schema-change工具。

先说结论:旧版本 MySQL 加索引锁表是因为使用了 COPY 算法,新版本通过 Online DDL 机制可实现不锁表,但需确认版本支持和操作类型。

  • 适合:MySQL 5.6+ 版本,添加二级索引、删除索引等轻量操作
  • 重点看:执行前用ALGORITHM=INPLACE, LOCK=NONE测试是否报错
  • 别忽略:长事务会阻塞 MDL 锁,导致 DDL 等待甚至超时

命令速用版

在 MySQL 5.6+ 环境中,添加索引的标准安全写法如下,显式指定算法和锁级别可防止默认行为退化为锁表:

ALTER TABLE table_name ADD INDEX idx_column (column_name) ALGORITHM=INPLACE, LOCK=NONE;

若报错提示ALGORITHM=INPLACE is not supportedLOCK=NONE is not supported,说明当前操作无法在线执行,需改用pt-online-schema-change

为什么会这样

锁表本质是 DDL 执行期间需要独占表资源以保证数据一致性。MySQL 5.6 之前主要使用 COPY 算法,需要创建临时表并拷贝数据,全程锁表。5.6 引入 Online DDL 后,支持 INPLACE 算法,允许在原地修改元数据或索引树,配合LOCK=NONE参数可允许并发 DML 操作。但并非所有 DDL 都支持,例如修改主键、收缩 CHAR 长度或在非空表加全文索引仍会触发 COPY 算法导致锁表。

分步处理

执行大表加索引前,按以下步骤操作可降低风险:

1. 确认版本和引擎:执行SELECT VERSION();确认版本≥5.6,SHOW CREATE TABLE确认引擎为 InnoDB(MyISAM 不支持 Online DDL)。

2. 检查参数支持:执行ALTER TABLE table_name ALGORITHM=INPLACE, LOCK=NONE;(不带具体变更)或带变更语句测试,若报错则说明不支持无锁变更。

3. 检查长事务:查询information_schema.INNODB_TRX,确保无长时间运行的事务,避免 MDL 锁等待。

旧版本 MySQL 在线 DDL 加索引锁表新版本如何避免

4. 执行变更:在业务低峰期执行带参数的 ALTER 语句,若使用 pt-osc 需确保无外键冲突或指定`--alter-foreign-keys-method`

5. 监控状态:执行期间观察SHOW PROCESSLIST,确认状态非Waiting for table metadata lock

怎么验证是否生效

变更完成后,通过以下方式验证是否发生锁表或异常:

1. 检查慢查询日志:确认 DDL 执行期间无大量 DML 超时记录。

2. 查看错误日志:确认无Lock wait timeout exceeded错误。

3. 验证索引存在:使用SHOW INDEX FROM table_name;确认新索引已建立。

4. 业务验证:观察应用侧监控,确认 DDL 期间无大量请求失败或延迟突增。

常见坑

1. 默认参数风险:LOCK=DEFAULT可能由 MySQL 自动降级为共享锁或排他锁,大表或低版本上容易误判,必须显式指定LOCK=NONE

旧版本 MySQL 在线 DDL 加索引锁表新版本如何避免

2. 外键约束:Online DDL 对外键支持有限,若表存在外键约束,pt-osc 可能无法执行或需特殊参数处理。

3. 磁盘空间:Online DDL 虽不锁表但仍可能产生临时文件,pt-osc 需要双倍磁盘空间创建新表,需提前检查tmpdir和数据盘剩余空间。

4. 主从延迟:在主库执行 DDL 后,从库回放 binlog 时可能因单线程 SQL 应用导致延迟突增,建议在从库先执行或评估延迟风险。

常见问题

MySQL 5.6 以下版本加索引一定锁表吗?

是的,MySQL 5.6 之前 InnoDB 引擎执行 DDL 通常采用 COPY 算法,会阻塞读写操作,无法实现在线无锁变更。

pt-online-schema-change 和 Online DDL 怎么选?

优先使用 Online DDL,因为它资源消耗少且速度快;当 Online DDL 不支持该操作或无法接受任何元数据锁等待时,再选择 pt-osc。

加索引期间为什么还会出现 Waiting for table metadata lock?

因为 DDL 提交阶段需要升级 MDL 锁,若此时有未提交长事务持有 MDL 读锁,DDL 会被阻塞,需杀掉长事务或等待其提交。

参考来源

Percona Toolkit Documentation: pt-online-schema-change, https://docs.percona.com/percona-toolkit/pt-online-schema-change.html

MySQL Official Documentation: Online DDL, https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl.html