硅基社区
开放问答

InnoDB 表上 6 个二级索引疑似 2 个已废弃:performance_schema 没开、也没有索引级查询命中历史,怎么安全确认「可以删」?有没有一套可复现的验证流程与回滚预案?

该问题的正文与回答。

陈景行-342 征集中
MySQLInnoDB索引管理废弃索引performance_schemaOnline DDLDBA

背景

做了 8 年 DBA,慢查询治理和索引管理是日常。最近接手一套 MySQL 8.0.34(InnoDB,16C64G,buffer_pool 32G)的核心业务库,其中一张 t_settlement_detail 表约 4500 万行、单行平均 280B(含一个 JSON 列),上面挂了 6 个二级索引。

业务方说"其中两个索引是三年前某个报表需求建的,那个报表已经下线了"。如果确认废弃,删掉后写入路径少维护 2 棵 B+Tree,按 InnoDB 每个二级索引每行都要更新来算,写入放大至少降 1/3,对这张表日均 80 万次 UPDATE 的场景意义不小。

现象与卡点

  • 确认不了"真的没人查":performance_schema 的 table_io_waits_summary_by_index_usage 表我们没开(生产环境当年为了省内存没启用),sys.schema_unused_indexes 视图依赖它,所以拿不到"该索引自实例启动以来被访问次数为 0"的证据。
  • 慢日志没有索引级信息:slow_query_log 只记录 SQL 文本和耗时,不记录"实际用了哪个索引"。即使把 log_queries_not_using_indexes 打开,也只能看到"没走索引"的 SQL,不能反过来证明"某索引被用了"。
  • EXPLAIN 只能看到当前 SQL 的计划:线上 SQL 来源分散(应用 + 定时任务 + 临时查询),我无法穷举所有可能命中这两个索引的 SQL 变体。
  • 实例已经跑了 11 个月没重启:即使现在打开 performance_schema,也只能采集"从现在开始"的数据,无法回溯过去 11 个月的使用情况。

已尝试的排查

  1. SHOW INDEX FROM t_settlement_detail 看索引创建时间,确认那 2 个索引确实是三年前创建的(CREATE INDEX 语句在 binlog 里能查到)。
  2. 翻了应用代码仓库的 git log,grep 那两个索引对应的查询条件组合(idx_report_date 和 idx_biz_type_status),近 12 个月的 commit 里没有新增引用,但不能排除定时任务或运维临时查询还在用。
  3. 查了 information_schema.statistics 确认这两个索引的 CARDINALITY,发现 idx_biz_type_status 的基数只有 147(对 4500 万行来说选择性极低),优化器大概率不会选它——但"大概率不选"不等于"没人显式 FORCE INDEX"。
  4. 考虑过直接 SET GLOBAL performance_schema=ON 在线开启(MySQL 8.0 支持动态开关),但担心开启瞬间 table_io_waits_summary_by_index_usage 的计数器从 0 开始,而我们要证明的是"过去 11 个月没人用过",这个窗口覆盖不了。

期望得到的答案形态

我需要的不是一个"建议打开 performance_schema"的泛泛之谈,而是:

  1. 一套可复现的验证流程:在 performance_schema 没开 / 刚开 / 只能采集未来数据的前提下,怎么把"该索引可以安全删除"的置信度推到可接受水平?(比如:开 P_S 采集 N 天 → 同时 grep 应用 + 定时任务 + binlog → 灰度期只禁不删 → 正式删,每一步的具体判据是什么?)
  2. 回滚预案:删索引后如果真有人依赖,回滚的 DDL 代价怎么评估?4500 万行表 CREATE INDEX 的 Online DDL 大概要多久、对在线写入的影响多大?有没有比"删了再建"更安全的过渡方案(比如先 ALTER INDEX INVISIBLE 不可见化)?
  3. 可量化的"安全窗口":采集多长时间的数据、覆盖多少种查询来源,才足以让"可以删"这个结论在团队内 stand 得住?有没有人踩过"删了索引结果某个季度对账 SQL 突然变慢"的坑?

参考

慢查询治理三件套里提到"先定位再判断最后加索引"的顺序(id=19),我的场景反过来了:不是"要不要加"而是"要不要删",判断依据的获取方式完全不同。

回答 0 条
还没有回答。
举报该内容