mysql如何管理索引的生命周期_mysql索引维护指南

4次阅读

应删除长期未被使用或与其他索引重复的索引;通过information_schema.statistics和performance_schema.table_io_waits_summary_by_index_usage确认使用情况,冗余复合索引如INDEX(a,b)与INDEX(a)共存时通常可删INDEX(a)。

mysql如何管理索引的生命周期_mysql索引维护指南

什么时候该删掉一个索引

索引不是越多越好,冗余或低效的索引会拖慢写入、占用磁盘、增加优化器决策负担。判断要不要删,核心看两点:有没有被用到,以及是否和其他索引重复。

先查 information_schema.statistics 或用 SHOW INDEX FROM table_name 看索引定义;再结合 performance_schema.table_io_waits_summary_by_index_usagemysql 8.0+)确认实际命中次数——长期 COUNT_STAR = 0 的索引基本可以标记为待清理。

  • 复合索引 INDEX (a, b) 和单独索引 INDEX (a) 共存时,后者大概率冗余(除非有 WHERE a = ? ORDER BY b DESC 这类需要单独排序的场景)
  • ALTER TABLE ... DROP INDEX 不锁表(Online DDL),但大表仍建议在低峰期执行
  • 删除前用 EXPLAIN select ... 对比关键查询的执行计划,防止误伤

如何安全地重建低效索引

索引碎片化、统计信息过期、页分裂严重时,SELECT 性能会下降,但直接 DROP + CREATE 有风险:中间空窗期查询可能走全表扫描,且大索引重建过程阻塞写入(尤其 MySQL 5.7 及更早版本)。

  • 优先用 OPTIMIZE TABLE table_name(InnoDB 下本质是重建表 + 索引,需额外磁盘空间)
  • MySQL 5.6+ 支持 ALTER TABLE ... ALgoRITHM=INPLACE, LOCK=NONE 重建单个索引,例如:ALTER TABLE t1 DROP INDEX idx_a, ADD INDEX idx_a (a) ALGORITHM=INPLACE
  • 重建后务必执行 ANALYZE TABLE table_name,否则优化器可能继续用旧的统计信息做错误判断

哪些操作会意外让索引失效

不是 SQL 写错才失效,很多看似合理的写法在底层无法走索引,比如隐式类型转换、函数包裹字段、模糊查询左匹配等。

  • WHERE phone = 13800138000(phone 是 VARCHAR)→ 触发隐式转换,索引失效
  • WHERE date(create_time) = '2024-01-01' → 函数作用于索引列,无法使用索引
  • WHERE name LIKE '%abc' → 左模糊,B+Tree 无法从头定位
  • WHERE status IN (1,2,3) AND create_time > '2024-01-01' → 如果复合索引是 (create_time, status),顺序反了也用不上

监控索引使用情况的最小可行方案

不依赖外部工具,只用 MySQL 自带能力就能快速摸清索引真实价值。重点不是“有没有”,而是“谁在用、怎么用、用了多少次”。

  • MySQL 8.0+:查 performance_schema.table_io_waits_summary_by_index_usage,关注 COUNT_READ 字段,值为 0 且存在超过一周可预警
  • 所有版本:开启慢查询日志 + log_queries_not_using_indexes = ON,但注意它只记录“完全没走索引”的语句,对部分走索引的无效查询无感知
  • 定期跑 SELECT * FROM sys.schema_unused_indexes(sys schema 需要初始化),它基于 performance_schema 数据聚合,比手写 SQL 更准

真正麻烦的不是建错索引,而是没人定期看它还活不活着。索引没有自动退休机制,得靠人盯住那些半年没被 SELECT 触碰过的 INDEX 名字。

text=ZqhQzanResources