首页 > 数据库 >如何利用MySQL sys库排查从未使用的废弃索引?

如何利用MySQL sys库排查从未使用的废弃索引?

来源:互联网 2026-07-21 08:30:19

使用sys.schema_unused_indexes排查废弃索引时需谨慎:该视图仅反映performance_schema采集周期内未被查询选中的索引,重启或采集时间过短易产生假阴性。需确认events_statements_history_long启用且数据非零,并保证业务高峰期持续采集至少24小时。还应交叉验证table_io_waits_summar

在MySQL索引优化实践中,sys.schema_unused_indexes视图常被用于识别废弃索引,但许多开发者对其存在误读。该视图反映的是performance_schema采集周期内未被查询选中的索引情况,而非绝对意义上的“从未被使用”。若MySQL刚重启或采集时间不足,COUNT_FETCH字段全为零,此时输出的结果多为假阴性,需谨慎对待。

在采取任何索引删除操作之前,务必完成以下三项前置确认:

长期稳定更新的攒劲资源: >>>点此立即查看<<<

  • 检查performance_schema.setup_consumers表中events_statements_history_long是否已启用。若该消费者关闭,sys.schema_unused_indexes将无数据可读取。
  • 执行SELECT COUNT(*) FROM events_statements_history_long,返回非零值才说明语句采集功能正常运作。
  • 确保在业务高峰期持续采集至少24小时,尤其需覆盖定时任务、报表SQL等低频但关键的业务查询。

如何利用MySQL sys库排查从未使用的废弃索引?

直接查询sys.schema_unused_indexes但必须确认数据可信

该视图的判定逻辑并非“索引建了没用就报出”,而是“在performance_schema已采集的查询中一次都未被选中”。MySQL刚重启或采集时间过短时,COUNT_FETCH全部归零,结果将呈现大量假阴性。

实际操作前务必执行以下检查:

  • SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE 'events_statements_%' AND ENABLED = 'NO' —— 若events_statements_history_long被关闭,sys.schema_unused_indexes将失去数据来源
  • SELECT COUNT(*) FROM performance_schema.events_statements_history_long —— 非零值才表明语句采集已生效
  • 在业务高峰期持续采集至少24小时,尤其要覆盖定时任务、报表SQL等低频但关键的查询场景

不可仅依赖sys.schema_unused_indexes输出,需交叉验证COUNT_FETCH

该视图仅告知索引“未被使用”,但无法区分是真闲置还是未进入采样窗口。更可靠的判断依据来自底层统计表:

SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, COUNT_FETCH, COUNT_READ FROM performance_schema.table_io_waits_summary_by_index_usage WHERE OBJECT_SCHEMA = 'your_db' AND INDEX_NAME = 'idx_xxx'

重点关注COUNT_FETCH和COUNT_READ是否均为零。若任一字段非零,说明索引确实被使用过;若均为零,需结合EXPLAIN和慢日志进一步判断是否存在漏采。

联合索引中部分列未使用不会被sys.schema_unused_indexes标记

例如存在INDEX(a, b, c),但业务查询中仅出现WHERE a = AND c = ,优化器仍可能选择该索引(key字段显示索引名),但实际仅用到a列,c列因跳过b列而完全失效。

此时需通过EXPLAIN查看执行细节:

  • key_len明显小于理论最大值 —— 说明仅使用了前缀列
  • Extra字段出现Using where但未出现Using index —— 表明未走覆盖扫描,大概率发生回表且部分列未参与过滤
  • 对于ORDER BY场景,即使WHERE子句未使用全部列,只要排序能被索引覆盖,索引仍可能被选中,不能仅凭key字段存在就判定索引有效

删除索引前必须人工核验三类隐性依赖

自动化脚本输出的“可删除列表”仅为起点,真正危险的是那些不显山露水的隐性依赖:

  • SELECT COUNT(*) FROM t WHERE ... 类聚合查询常走索引快速计数,但不会在table_io_waits_summary_by_index_usage中高频出现
  • CARDINALITY极低的索引(如status列仅3个值)即使COUNT_FETCH为零也本就不该存在,删除它不解决问题,需重构设计
  • ORM框架隐式调用:Django的.exists()、Laravel的doesntExist()会生成SELECT 1 FROM t WHERE ...,这类语句轻量但关键,容易被忽略

索引是否真正废弃,不取决于它是否出现在执行计划中,而取决于删除后是否会导致某条SQL从ref降级为ALL。这一判断无法全自动化,必须由人工盯住慢日志和核心路径的EXPLAIN结果来最终确认。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备2026025700号-3 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。