直接删除索引用 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是否突增 删索引最危险的不是语法写错,而是删掉一个正在默默支撑着某个边缘查询路径的索引——它平时不显眼,一删就让某条报表 SQL 从 200ms 涨到 12s。
