线上系统跑着,突然要加个索引优化查询,可一执行 ALTER TABLE,表直接锁了,业务卡住,用户开始抱怨。这种情况不少见,尤其是在高并发场景下,传统方式建索引等于给数据库“动手术”,谁都怕出问题。
MySQL 5.6 以后的在线 DDL
其实从 MySQL 5.6 开始,InnoDB 引擎就支持部分 DDL 操作的“在线”执行,也就是允许在创建索引时不阻塞 DML(增删改查)。关键在于使用 ALGORITHM=INPLACE 和 LOCK=NONE 参数。
ALTER TABLE user_info ADD INDEX idx_mobile (mobile), ALGORITHM=INPLACE, LOCK=NONE;
只要语句满足条件,InnoDB 就不会复制整张表,也不会长时间加锁。不过要注意,并不是所有字段类型和索引类型都支持这种方式。比如 TEXT 或 BLOB 字段上的索引,可能还是会退化为 COPY 模式,导致锁表。
pt-online-schema-change 工具实战
如果版本较老,或者操作复杂,推荐 Percona Toolkit 中的 pt-osc。它通过创建影子表、触发器同步数据、逐步迁移的方式,实现真正意义上的“不锁表”。
举个例子,想给订单表加个用户状态索引:
pt-online-schema-change --alter \"ADD INDEX idx_status (status)\" D=shop_db,t=orders --execute
运行后,工具会自动创建新表,把原表数据慢慢拷过去,同时用触发器保持两边一致。等数据追平,再原子性替换原表。整个过程应用几乎无感,只是对主从延迟敏感的环境要注意观察。
阿里云 RDS 的 Online DDL 优化
如果你用的是阿里云 RDS,可以留意它的增强版 Online DDL。在控制台或参数设置里开启相关选项后,一些原本会锁表的操作会被优化成后台异步执行。比如在低峰期发起建索引任务,系统自动调度,避免影响白天高峰流量。
实际注意事项
别以为“不锁”就万事大吉。像 pt-osc 这类工具会频繁写触发器,增加主库压力;而 Online DDL 在执行时仍可能有短暂的元数据锁(MDL),尤其在提交阶段。曾经有个案例,一个开发在晚上8点跑索引,虽然用了 INPLACE,但恰逢流量高峰,MDL 锁住了查询,页面还是卡了几秒。
所以建议:重要操作尽量放在低峰期,提前在测试环境模拟,监控好 IOPS 和复制延迟。加索引不是难事,关键是选对方法,踩准节奏。