冗余和重复索引会显著降低写入性能,每次insert/update/delete都必须同步更新所有相关索引的b+树,导致页分裂激增、change_buffer失效、锁竞争加剧,实测批量写入耗时可下降30%~50%。

冗余和重复索引对写入性能的影响不是“可能变慢”,而是每次 INSERT/UPDATE/DELETE 都会实实在在多执行一次甚至多次 B+ 树操作——只要索引存在,MySQL 就必须维护它。
看 INFORMATION_SCHEMA.INNODB_METRICS 中的页分裂和索引更新指标
真正反映写入压力的不是慢查询日志,而是 InnoDB 内部统计。重点关注这几个指标:
-
index_page_splits:值持续上升,说明索引页频繁分裂,尤其是长字符串或无序插入场景下,冗余索引会让这个数字翻倍 -
dml_inserts与index_fetches的比值异常低(比如每 1 次插入触发 5+ 次索引查找),暗示有多个索引在同步更新 -
change_buffer_operations如果远低于预期(如innodb_change_buffering = all但该值几乎为 0),说明大量写入被唯一索引或全表扫描式索引阻塞,无法走 change buffer 缓存
用 pt-duplicate-key-checker 直接识别结构重复的索引
手查 information_schema.STATISTICS 容易漏掉前缀长度、排序方向、列顺序等细节。而 pt-duplicate-key-checker 能精确识别真正可删的索引:
- 输出中标记为
duplicate的,是完全相同的索引(如idx_a和idx_a_bak都建在(email)上) - 标记为
redundant的,是前缀覆盖关系(如已有(user_id, status),再建(user_id)就是冗余) - 注意它不报告
(status, user_id)这类“顺序不同但字段相同”的索引——那不算冗余,只是低效,需结合EXPLAIN判断是否被实际使用
对比删索引前后的批量写入耗时(别信单条语句)
单条 INSERT 很难看出差异,要测真实影响,得模拟业务写负载:
- 用
sysbench或真实业务 SQL 批量插入 10 万行,记录耗时;然后DROP INDEX冗余索引后重跑,观察耗时下降比例(实测常见 30%~50%) - 重点观察
SHOW PROCESSLIST中状态是否从大量updating index变为query end或commit - 如果删的是唯一索引,还要检查
innodb_row_lock_waits是否明显回落——这说明锁竞争减轻了
最容易被忽略的点:唯一索引 + 长字段 + 高频更新 = 写入雪崩
很多人只盯着“有没有索引”,却没算清三重叠加成本:一个 VARCHAR(500) 字段加了 UNIQUE 约束,每次 INSERT 不仅要校验重复(强制走磁盘查找)、还要存大值(页分裂快)、且该字段又常被 UPDATE(触发删除旧索引项 + 插入新项)。这种组合在高并发注册场景下,INSERT ... ON DUPLICATE KEY UPDATE 可能直接卡住整个连接池。删之前,先确认应用层是否真依赖这个唯一性语义——有时用应用层去重 + 异步校验更稳。











