当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL sys.schema_unused_indexes 的结果为什么不能直接删索引

MySQL sys.schema_unused_indexes 的结果为什么不能直接删索引

来源:17golang原创 2026-09-14 23:57:36 0浏览 收藏

看到 sys.schema_unused_indexes 里出现一个索引,不能马上执行 DROP INDEX。这个视图表达的是:在当前 MySQL 实例、当前 Performance Schema 统计周期内,没有记录到该索引的 I/O 事件。它不是业务代码的“永久不用证明”。实例刚重启、报表只在月底运行、统计信息被清零,都会让结果暂时失真。

要点速览
  • schema_unused_indexes 是候选清单,先看观察窗口是否覆盖峰值、批处理和低频任务。
  • 索引可能承担唯一性、外键、排序或备用查询路径,不能只凭“没有事件”判断可删。
  • 先用 invisible index 做可恢复停用,再比较 EXPLAIN、慢查询和业务指标。
  • 真正删除前保留 SHOW CREATE TABLE 里的索引定义,并安排可重建方案。
MySQL sys.schema_unused_indexes 从 Performance Schema 索引事件汇总到候选索引的关系示意图
图1:统计观察示意图,展示未使用索引视图与 Performance Schema、业务工作负载之间的边界,不代表真实运行截图。

先把“未使用”还原成统计数据的快照

这个视图只有三个关键字段:库名、表名和索引名。它的上游是 performance_schema.table_io_waits_summary_by_index_usage,按表索引汇总 I/O 等待;其中 PRIMARY 表示使用主索引,NULL 表示没有使用索引,插入操作也会计入 INDEX_NAME = NULL。因此,视图回答的是“有没有被监测到事件”,不是“应用层是否设计上需要它”。

-- 先查看候选索引,并限定到目标业务库,避免误读系统库
SELECT object_schema, object_name, index_name
FROM sys.schema_unused_indexes
WHERE object_schema = 'shop'
ORDER BY object_name, index_name;

-- 同时记录统计来源;Performance Schema 数据属于当前实例,重启后不会保留
SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME,
       COUNT_STAR, COUNT_READ, COUNT_WRITE
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE OBJECT_SCHEMA = 'shop'
  AND OBJECT_NAME = 'orders';

MySQL 官方特别提醒:服务器必须运行足够久,而且处理的流量要能代表真实工作负载,否则出现在这个视图里的索引不一定有意义。维护前先记下实例启动时间、最近一次统计清零时间、DDL 变更时间,并确认观察窗口包含白天高峰、夜间任务、月末报表和故障补偿任务。若刚执行过 TRUNCATE TABLE performance_schema.table_io_waits_summary_by_table,之前的观察不能直接拿来做删除结论。

从表定义和真实 SQL 查出索引的隐藏职责

候选索引还要经过三层交叉检查。第一层是表定义:看它是否是唯一索引、外键相关索引,是否被某些排序或连接条件使用。第二层是应用代码、定时任务和运维脚本:低频导出、租户切换、数据修复往往不会出现在日常流量里。第三层是执行计划:对照核心 SQL 的 possible_keyskeyrowsExtra,确认优化器是否曾经把它作为可行路径。

-- 保存定义和可见性,后续可据此写回滚脚本
SHOW CREATE TABLE shop.orders;
SHOW INDEX FROM shop.orders;

-- 用真实条件观察优化器当前选择;示例 SQL 需替换成业务语句
EXPLAIN SELECT order_id, customer_id, created_at
FROM shop.orders
WHERE customer_id = 2088
  AND status = 'paid'
ORDER BY created_at DESC
LIMIT 50;
观察结果说明下一步
长时间无事件且无业务依赖更像冗余候选,但仍需灰度停用进入 invisible index 试验
只在低频窗口使用日常统计不足以代表全年负载延长观察,补看任务和报表
承担唯一性或约束语义性能视图不能覆盖完整数据语义保留,另行评估结构变更
EXPLAIN 计划会选择它候选清单与当前计划出现冲突先查统计清零、计划样本和版本差异

真正决定删除的是停用验证,不是候选清单

对普通二级索引,MySQL 支持把索引设为 INVISIBLE。默认情况下优化器不会使用它,但索引还在,恢复为 VISIBLE 比重新创建更容易。这个阶段要在副本、灰度实例或明确的低风险窗口进行,并为核心查询保留计划对比。

-- 先让优化器忽略索引,停用前确认它不是 PRIMARY KEY
ALTER TABLE shop.orders
  ALTER INDEX idx_customer_status INVISIBLE;

-- 逐条对比关键查询的计划;只对本次语句临时启用 invisible index
EXPLAIN SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */
  order_id, customer_id, created_at
FROM shop.orders
WHERE customer_id = 2088 AND status = 'paid'
ORDER BY created_at DESC LIMIT 50;

-- 发现慢查询、错误或计划恶化时立即恢复
ALTER TABLE shop.orders
  ALTER INDEX idx_customer_status VISIBLE;

停用后观察的不只是单条 EXPLAIN:还要看慢查询数量、关键接口延迟、批处理耗时、锁等待和错误日志。官方文档列出的可见信号包括执行计划改变、原本不慢的查询进入慢查询日志,以及 Performance Schema 中受影响工作负载增加。若索引被 hint 明确引用,设为 invisible 还可能直接暴露错误,这正是提前灰度的价值。

MySQL invisible index 停用试验连接执行计划慢查询与恢复动作的静态关系示意图
图2:停用验证示意图,展示 invisible index 与查询计划、慢查询、Performance Schema 和恢复动作的关系,不代表真实运行结果。

满足删除条件后,保留一条可回滚的结构变更记录

只有当观察窗口覆盖真实任务、停用期间没有计划和业务指标恶化、索引也不承担约束语义时,才进入删除。删除本身会改变表结构,InnoDB 在线 DDL 是否适合当前表,还要结合表大小、并发写入、锁策略和发布窗口判断。

-- 删除前再次确认索引名,避免把相似名称写错
SHOW INDEX FROM shop.orders
WHERE Key_name = 'idx_customer_status';

-- 在已审批的变更窗口执行;具体 ALGORITHM/LOCK 需按环境评估
DROP INDEX idx_customer_status ON shop.orders;

-- 回滚脚本示例:保留原始列顺序和索引定义,禁止临时猜列
CREATE INDEX idx_customer_status
  ON shop.orders (customer_id, status);

最终记录至少包括:候选查询时间、实例运行和统计周期、索引原始定义、覆盖过的业务任务、停用开始与结束时间、关键 SQL 计划差异、指标结论以及重建 DDL。这样以后即使业务新增查询,也能知道这次删除基于什么证据,而不是把一行视图结果当成永久事实。

常见问题

视图里没有索引事件,是不是索引一定没用?

不是。它只代表当前实例和统计周期没有观测到事件,低频任务、重启或清零都可能造成空结果。

把索引设为 invisible 会立即释放磁盘吗?

不会。invisible 主要改变优化器是否考虑该索引,索引结构仍然存在;要释放空间需要经过正式删除和相应的表空间处理。

为什么 EXPLAIN 还会显示这个索引?

如果使用了 use_invisible_indexes=on 的会话设置或提示,优化器可以把 invisible index 纳入计划构造;排查时要记录会话级设置。

可以直接用 DROP INDEX 试错吗?

不建议。先 invisible 灰度并保留原始建索引语句,确认真实业务没有退化后再做结构变更。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
SkildArt跨境素材项目如何估算本地化工时?语言复核、尺寸适配与返工拆分SkildArt跨境素材项目如何估算本地化工时?语言复核、尺寸适配与返工拆分
上一篇
SkildArt跨境素材项目如何估算本地化工时?语言复核、尺寸适配与返工拆分
Go embed 同名文件来自多个目录时如何避免构建失败
下一篇
Go embed 同名文件来自多个目录时如何避免构建失败
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    26次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    130次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    62次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    23次使用
  • OpenCompass大模型评测体系详解:功能、使用指南与应用场景
    OpenCompass
    OpenCompass是上海AI实验室推出的开源大模型评测平台,提供CompassKit、CompassHub和CompassRank三大核心组件,支持LLM及多模态模型的一站式标准化评估与排行榜查询。
    81次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码