mysql中删除索引与性能优化

来源:这里教程网 时间:2026-02-28 20:37:52 作者:

删除索引前必须确认它是否被查询实际使用

很多团队一看到“某个索引没被创建时的字段”就直接删,结果线上

SELECT
变慢、
EXPLAIN
显示全表扫描。MySQL 不会主动告诉你哪个索引正在被用——得自己查。最可靠的方式是开启
performance_schema
中的
table_io_waits_summary_by_index_usage
表(MySQL 5.6+),或用
sys.schema_unused_indexes
视图(需启用
performance_schema
并加载
sys
库)。

注意:

INFORMATION_SCHEMA.STATISTICS
SHOW INDEXES
只告诉你“有”,不告诉你“用没用”。临时禁用索引(
ALTER TABLE ... DISABLE KEYS
)在 InnoDB 中无效,别试。

检查是否真没用:
SELECT * FROM sys.schema_unused_indexes WHERE object_schema = 'your_db';
若没开
performance_schema
,至少跑一周慢查询日志 +
pt-index-usage
工具分析
复合索引中部分字段被查询用到(比如
(a,b,c)
上只查
a = ?
),该索引仍算“被使用”,不能仅因
c
没出现就删

DROP INDEX
语句本身会锁表(InnoDB 下取决于 MySQL 版本)

MySQL 5.6 之前,

DROP INDEX
会触发表重建,整个过程阻塞 DML;5.7+ 支持
ALGORITHM=INPLACE
的在线 DDL,但仍有条件限制:索引不是主键、不涉及全文/空间索引、且表引擎为 InnoDB。

执行前务必确认版本和存储引擎,否则可能在高峰期卡住业务写入。

安全写法(显式指定算法):
ALTER TABLE t1 DROP INDEX idx_name, ALGORITHM=INPLACE, LOCK=NONE;
若报错
ALGORITHM=INPLACE is not supported
,说明不满足条件,得切到低峰期用
ALGORITHM=COPY
(会锁表)
主键索引不能用
DROP INDEX
删除,必须用
ALTER TABLE ... DROP PRIMARY KEY
,且会重建聚簇索引,代价极高

删除索引后写入变快,但某些查询可能陡然变慢

索引本质是“以空间换时间”的冗余结构。删掉一个索引,

INSERT
/
UPDATE
/
DELETE
的维护开销下降,但原本走索引的
WHERE
ORDER BY
JOIN
可能退化为文件排序或临时表,CPU 和 I/O 压力反而上升。

尤其要注意覆盖索引场景:如果一个

SELECT a,b FROM t WHERE c=?
原本命中
(c,a,b)
覆盖索引,删掉后变成回表+排序,延迟可能翻几倍。

删索引前,用
EXPLAIN FORMAT=JSON
对核心 SQL 重跑执行计划,比对
key
rows
extra
字段变化
监控删索引后
Handler_read_rnd_next
(随机读行数)和
Sort_merge_passes
是否激增
批量导入场景下,可临时删非关键索引加速写入,但导入完必须立刻重建——别忘了

唯一索引与外键约束不能随便删

唯一索引(含主键)不只是性能结构,更是数据完整性保障。删掉唯一索引后,应用层插入重复值不会报错,直到唯一约束失效引发脏数据;外键索引被删会导致

ALTER TABLE ... DROP FOREIGN KEY
失败,因为 MySQL 要求外键字段必须有索引支撑。

这类索引哪怕“看起来没被查询用”,也不能按普通索引处理。

检查是否为外键索引:
SELECT CONSTRAINT_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME = 't' AND REFERENCED_TABLE_NAME IS NOT NULL;
检查是否为唯一约束:
SHOW CREATE TABLE t
中找
UNIQUE KEY
PRIMARY KEY
真要删,必须同步评估业务逻辑能否容忍重复、级联操作是否可控、下游服务是否依赖该约束语义

真正难的不是语法怎么写,是判断“这个索引到底是不是冗余”——它可能在某个凌晨三点的报表任务里悄悄扛着压力,也可能在某个未覆盖的异常分支里唯一生效。删之前,看数据,看执行计划,看监控曲线,别信名字,也别信直觉。

相关推荐