MySQL添加复合索引并删除旧索引的最佳实践及单语句安全性咨询
问题解答
1. 单条SQL语句能否完成操作?
可以,且完全符合你的需求。
MySQL在处理单条ALTER TABLE包含多个操作时,会优先执行所有ADD INDEX类的添加操作,待新索引创建完成后,再执行DROP INDEX类的删除操作,不会出现先删旧索引、表临时无索引的状态。
同时,单条ALTER TABLE是原子操作:要么所有操作执行成功,要么全部回滚,不会出现半完成的中间状态,保障数据一致性。
你提供的SQL语句是可行的:
ALTER TABLE my_table ADD INDEX idx_c1_c2 (c1, c2), DROP INDEX idx_c1;
2. 低性能开销的推荐方案
优先使用单条原子ALTER语句
对于MySQL 5.6及以上版本的InnoDB表(数据量较大但未到TB级),这种方式开销最低:
- InnoDB支持在线DDL,添加/删除索引过程中,仅在最后同步元数据阶段有短暂锁表,业务可正常读写。
- 单条语句仅需一次表数据扫描(创建复合索引时),比分开执行两条
ALTER的开销更小(两条语句会扫描两次表)。
超大规模表的优化方案
如果是TB级超大表,即使在线DDL也可能带来明显负载,可采用:
- 使用第三方在线DDL工具:如Percona的
pt-online-schema-change或GitHub的gh-ost,通过复制表数据、同步增量变更的方式完成索引修改,全程无锁表,对业务影响极小。 - 选择业务低峰期执行:避开流量高峰,降低对用户体验的影响。
- 提前监控系统负载:执行前确认CPU、磁盘IO、内存有足够余量支撑DDL操作。
额外注意事项
- 复合索引
(c1,c2)的前缀列是c1,所有原本依赖单列索引idx_c1的查询,都可通过新复合索引完成,删除旧索引不会影响这类查询的性能。 - 若MySQL版本低于5.6,InnoDB的
ALTER TABLE会锁表,建议使用第三方工具避免长时间锁表。
内容的提问来源于stack exchange,提问作者Jacky Wang




