隐藏索引被优化器无视需双重验证:查INFORMATION_SCHEMA.STATISTICS中IS_VISIBLE='NO',且EXPLAIN中key字段不再出现该索引;同时确认optimizer_switch未启用use_invisible_indexes。

隐藏索引不是“不干活”,而是让优化器彻底跳过它——写入开销、磁盘占用、唯一性校验全在,但执行计划里压根不出现。想靠它测删除影响,必须先确认它真被忽略,否则观察全是假阳性。
怎么确认隐藏索引真的被优化器无视了
别只看 SHOW INDEX 的 Visible: NO,这容易误判。必须双重验证:
- 查系统表:
SELECT IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'orders' AND INDEX_NAME = 'idx_created_at',返回值是字符串'NO'(不是布尔值)才算生效 - 跑真实查询:
EXPLAIN SELECT * FROM orders WHERE created_at > '2026-01-01',对比切换前后的key字段:若之前走该索引、现在为空或换成了别的索引,才说明生效 - 检查会话级干扰:
SELECT @@optimizer_switch LIKE '%use_invisible_indexes=on%',如果返回1,说明当前会话手动打开了不可见索引支持,得关掉再测
为什么不能只看 performance_schema.table_io_waits_summary_by_index_usage
这个视图的 COUNT_STAR = 0 只代表近期没被统计到使用,不代表它没价值。低频但关键的查询(比如每小时一次的对账任务)可能完全漏掉。更危险的是:某些 SQL 用了 FORCE INDEX 或 USE INDEX 显式指定该索引,而这类语句不会出现在 io_waits 统计里。
- 真正要盯的是慢查询日志中是否新增了原本能走该索引的语句
- 监控
Handler_read_next和Handler_read_rnd_next是否突增——这是全表扫描或回表激增的信号 - 应用层接口超时率、P99 响应时间波动比 QPS 更敏感,尤其对短连接高频查询
切换前后必须关注的三个性能代价
隐藏 ≠ 删除,所有维护成本照旧。实测中常被低估:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 写入吞吐量下降约 8%–20%,与普通索引几乎一致;TPC-C 测试中 500 万行表加隐藏索引后,
INSERT吞吐量跌了 15% - 存储空间占用完全不变,InnoDB 仍为其分配页并更新统计信息
- 唯一索引即使隐藏,依然强制校验重复值,
INSERT冲突时照样报Duplicate entry
所以别长期挂着隐藏索引“占着茅坑”——测试窗口建议控制在 24 小时到 7 天,超过就得决策删或留。
ALTER INDEX INVISIBLE 真的毫秒级?小心元数据锁
语法上是 DDL,但 MySQL 8.0.12+ 虽支持 instant DDL,仍需获取元数据锁(MDL)。高并发写入场景下,ALTER TABLE orders ALTER INDEX idx_created_at INVISIBLE 可能短暂阻塞后续 DML。
- 新建索引时直接加
INVISIBLE(如CREATE INDEX idx_user_status ON users(status) INVISIBLE)可避开这步,也省去状态切换验证 - 切勿在业务高峰执行;优先选低峰期,或搭配
pt-online-schema-change做灰度(虽然它不原生支持 INVISIBLE,但可配合自定义 hook) - 主键、隐式主键依赖的唯一索引、
FULLTEXT和SPATIAL索引不支持隐藏,执行会直接报错ERROR 3522
最易被忽略的一点:跨版本迁移含 INVISIBLE 的表结构时,MySQL 5.7 或更低版本解析 mysqldump 输出会失败,导出必须加 --no-create-info 或手动清理 INVISIBLE 关键字。










