MySQL 8.0+ 推荐统一使用 ALTER TABLE ... DROP INDEX,DROP INDEX 为遗留语法且不推荐;删除前须确认是否被外键引用、是否被查询实际使用、是否承担唯一性保障。

直接删除索引用 DROP INDEX 还是 ALTER TABLE ... DROP INDEX?
MySQL 8.0+ 推荐统一用 ALTER TABLE ... DROP INDEX,DROP INDEX 语句虽仍支持,但只能在特定存储引擎(如 MyISAM)上独立使用,InnoDB 下必须绑定表名,实际等价于 ALTER TABLE 的简写形式。官方文档已明确将其标记为“legacy syntax”,后续版本可能弃用。
-
DROP INDEX idx_name ON tbl_name;—— 语法合法但不推荐,易被误认为可跨表操作 -
ALTER TABLE tbl_name DROP INDEX idx_name;—— 显式、安全、全引擎兼容,应作为默认选择 - 若索引是主键(
PRIMARY KEY)或唯一约束(UNIQUE),不能用idx_name直接删,得用DROP PRIMARY KEY或DROP CONSTRAINT(MySQL 8.0.19+ 支持后者)
删除前必须确认的三件事
索引不是随便删的,尤其在线上表。执行前务必查清:
- 该索引是否被
FOREIGN KEY引用?删错会触发ERROR 1553 (HY000): Cannot drop index 'xxx': needed in a foreign key constraint - 是否被查询实际使用?可通过
EXPLAIN SELECT ...或performance_schema.table_io_waits_summary_by_index_usage查看命中率;长期COUNT_STAR = 0的索引才值得删 - 是否为唯一性保障所依赖?例如邮箱字段的
UNIQUE索引,删了可能导致重复数据插入成功
ALTER TABLE ... DROP INDEX 的真实行为与锁影响
MySQL 5.6+ 对大多数 DDL 支持 ALGORITHM=INPLACE,但删索引属于轻量操作,默认走 inplace,不重建表,但仍需获取 MDL(metadata lock) 写锁——意味着删索引期间,所有对该表的 DML(INSERT/UPDATE/DELETE)和 DDL 都会被阻塞,直到语句完成。
- 大表删索引耗时极短(毫秒级),但若恰逢高并发写入,锁等待可能堆积,建议避开业务高峰
- 执行前可用
SHOW PROCESSLIST;检查是否有长事务持有该表的MDL,否则ALTER会卡住 - 不要在从库上直接删索引:除非你确定主从结构允许(如 GTID +
replicate_ignore_table),否则可能引发复制中断
复合索引部分字段失效 ≠ 可删,别被 EXPLAIN 误导
看到 key_len 比复合索引总长度小,就以为“没用上全部字段,可以删”?这是典型误解。比如索引 (a, b, c),查询 WHERE a = 1 AND b > 10 会用到前两列,key_len 显示只用了 a,b,但删掉这个索引,c 字段的排序或覆盖查询就可能退化为 filesort 或回表。
- 删索引前先跑
SELECT COUNT(*) FROM information_schema.STATISTICS WHERE table_name = 'tbl_name' AND index_name = 'idx_name';看是否还有其他列依赖该索引结构 - 用
pt-index-usage(Percona Toolkit)分析慢日志,比单看EXPLAIN更准 - 测试环境务必用真实流量压测,观察 QPS、延迟、
Innodb_buffer_pool_reads是否突增










