单列索引过多会直接拖慢insert/update/delete:每增一个索引,dml就得为每个二级索引执行一次b+树维护(定位、分裂、刷脏、写redo),5个索引时耗时达1个时的2.8倍,8个时翻4.5倍;高频更新字段、大字段前缀索引、json生成列索引、低基数字段索引及冗余前导列索引危害最大。

MySQL 中单列索引建得太多,会直接拖慢 INSERT、UPDATE、DELETE 这三类 DML 操作,不是“可能变慢”,而是每个操作都必须为每个索引单独执行一次 B+ 树维护——这是 InnoDB 写入路径上硬编码的开销。
每多一个索引,DML 就多一次完整维护
每次写入,InnoDB 不仅要写聚簇索引(主键),还要同步更新所有二级索引:定位页、分裂页(如需)、刷脏页、写 redo 日志。这个过程无法跳过或合并。
- 1 个索引时,单行 INSERT 耗时设为基准 1x
- 5 个索引时,实测耗时约 2.8x
- 8 个索引时,常见翻到 4.5x
哪些单列索引对 DML 杀伤力最大
不是所有索引代价一样,以下几类尤其危险:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
高频更新字段:比如
updated_at、status,哪怕只改一个字段,所有含它的索引都要重算节点 -
大字段前缀索引:如
VARCHAR(2000)上建INDEX(content(255)),更新时仍要截断、哈希、刷新整页 - JSON 生成列索引:JSON 一变 → 生成列值重算 → 所有依赖它的索引全量更新
-
低基数字段索引:如
gender、is_deleted,优化器基本不用,但 DML 照样维护 -
冗余前导列索引:已有
INDEX(user_id, status),再加INDEX(user_id)就是纯浪费
怎么验证真实影响
别靠猜测,用系统视图和日志抓证据:
- 查未使用索引:
SELECT * FROM sys.schema_unused_indexes(MySQL 8.0+),看哪些单列索引近 30 天零命中 - 查 DML 是否真在刷它:
performance_schema.table_io_waits_summary_by_index_usage中观察写等待次数 - 翻慢查询日志:如果 INSERT/UPDATE 频繁出现在 top 10,且
EXPLAIN FORMAT=JSON显示used_columns只用了其中 1–2 个索引,其余全是白干活
删索引前必须盯住业务依赖
删一个 INDEX(status) 很容易,难的是确认没有后台任务或报表正靠它加速 WHERE status = 'pending' 这类查询。
- 删前一周开启
slow_query_log,配合min_examined_rows = 1000抓流量,重点过滤含该字段的 WHERE 条件 - 对核心表,务必用
pt-online-schema-change --alter "DROP INDEX idx_status"替代原生DROP INDEX,避免锁表 - 删完后注意统计信息更新延迟:优化器可能沿用旧执行计划,导致某条 SQL 从
Using index退化成Using where; Using filesort










