不可见索引让优化器彻底无视它,但物理结构、写入开销和唯一性校验均保留;需用alter table alter index invisible切换,通过explain验证key为空或use index报错来确认失效,观察至少24小时真实负载。

直接说结论:用 ALTER TABLE ... ALTER INDEX ... INVISIBLE 把索引设为不可见,再观察至少24小时真实负载表现——这不是“删前预演”,而是让优化器彻底绕过它,同时保留所有物理结构和写入维护能力。
怎么确认某个索引真被优化器无视了
别信 SHOW INDEX FROM t 的 Comment 字段(它恒为 NULL),要看 Visible 列或查 INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE。更关键的是验证执行计划是否真的不走它:
-
EXPLAIN SELECT * FROM t WHERE col = 1;→ 如果key字段为空或走了别的索引,说明它已被忽略 -
EXPLAIN SELECT * FROM t USE INDEX (idx_name) WHERE col = 1;→ 若报错Unknown index 'idx_name',说明索引名错了;若能走,证明它物理存在且可用 - 注意:
FORCE INDEX会直接报错ERROR 1176 (42000): Key 'idx_name' doesn't exist,必须提前扫描代码/ORM 配置移除所有显式提示
为什么不能只看 performance_schema.table_io_waits_summary_by_index_usage
这个表里 COUNT_STAR = 0 只是基础参考,不是绝对依据。低频但关键的查询(比如月度报表、后台定时任务)可能完全不会出现在统计窗口里,但一旦触发就会全表扫描拖垮数据库:
- 它只记录已发生的索引使用事件,不预测潜在依赖
- 监控周期太短(默认每小时清空)容易漏掉偶发调用
- 建议搭配慢查询日志 +
Handler_read_next/Handler_read_rnd_next突增趋势一起看
压测时怎么闭环验证“删了到底会不会变慢”
核心是控制变量:不动表结构、不改应用、只动优化器行为。靠两步闭环:
- 先执行
ALTER TABLE t ALTER INDEX idx_name INVISIBLE; - 在压测连接中临时打开会话级开关:
SET SESSION optimizer_switch='use_invisible_indexes=ON';,再跑EXPLAIN FORMAT=JSON,对比开启/关闭该开关下的used_indexes和key字段是否消失 - 注意:全局设置
SET GLOBAL会影响所有新会话,生产环境严禁使用
最容易被忽略的三个落地坑
很多人以为设成 INVISIBLE 就万事大吉,结果在线上翻车:
- 备份恢复后索引仍是
INVISIBLE状态,mysqldump默认导出可见性属性,但xtrabackup等物理备份工具不保留该元数据,恢复后可能意外变回VISIBLE - 分区表上对某个分区的索引设为不可见,其他分区不受影响;但执行
ALTER TABLE ... REORGANIZE PARTITION后,所有分区索引可见性可能被重置,需事后复查 - 主键、唯一约束依赖的索引(包括隐式主键)无法设为不可见,尝试会报错
ERROR 3522 (HY000): A primary key index cannot be invisible
真正安全的下线节奏是:设为不可见 → 观察 24 小时以上真实流量 → 出现慢查询立刻 ALTER TABLE ... VISIBLE 回滚 → 确认无影响后再删。重建索引的成本远高于一次误删带来的故障修复成本。











