Invisible Index 未在 EXPLAIN 的 key 字段中显示是正常现象,因其默认对优化器不可见;正确验证方式是查询 INFORMATION_SCHEMA.STATISTICS 中 IS_VISIBLE = 'NO',并确认 use_invisible_indexes=ON 是否启用。

查不到执行计划里的索引名,不等于它被优化器忽略了——Invisible Index的“失效”往往不是没生效,而是你验证方式错了,或者压测开关没开。
EXPLAIN 里 key 字段为空,但索引其实是 INVISIBLE 的
很多人看到 EXPLAIN SELECT * FROM t WHERE col = 1 的 key 字段是 NULL 或走别的索引,就以为目标索引“失效”了。其实这只是正常行为:Invisible Index 默认对优化器完全不可见,根本不会进候选集,所以 EXPLAIN 压根不会列出它,更不会出现在 key 字段里。
- 正确验证方式是查
INFORMATION_SCHEMA.STATISTICS:SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx_col',确认IS_VISIBLE = 'NO' -
SHOW INDEX FROM t也能看,但得盯住Visible列(8.0.12+),别只信Comment字段(它恒为NULL) - 如果
EXPLAIN FORMAT=JSON输出里used_indexes出现了该索引名,说明它已被强制启用或use_invisible_indexes=ON生效了
FORCE INDEX 报错 “Key doesn't exist”,不是语法问题
SELECT * FROM t FORCE INDEX (idx_col) WHERE col = 1 直接报 ERROR 1176 (42000): Key 'idx_col' doesn't exist in table 't1',这不是 SQL 写错了,而是 Invisible Index 在解析阶段就被优化器“抹掉”了——它不参与元数据可见性校验,FORCE 无法绕过这层过滤。
- 这个报错反而是 INVISIBLE 生效的强信号;如果没报错且走了索引,那说明它根本不是 INVISIBLE 状态
- ORM 框架(如 Django 的
.extra(index='idx_col')、MyBatis 的<hint>USE INDEX(idx_col)</hint>)也可能触发同类报错,上线前必须全局grep -r "FORCE\|USE INDEX\|IGNORE INDEX" - 想临时绕过限制?只能先
ALTER TABLE t ALTER INDEX idx_col VISIBLE,不能靠 hint
慢查询突增,但 EXPLAIN 显示执行计划没变
切为 INVISIBLE 后,应用监控突然出现大量超时或 Handler_read_next 暴涨,可 EXPLAIN 却显示还是走某个索引——这说明优化器确实没选那个被隐藏的索引,但它原本承担的查询路径被其他索引或全表扫描替代了,而这种降级在单条 EXPLAIN 里看不到全局影响。
- 重点看
performance_schema.table_io_waits_summary_by_index_usage:对比切换前后COUNT_STAR和SUM_TIMER_WAIT是否有关键查询转移 - 开启慢查询日志后,用
mysqldumpslow -s t /var/log/mysql/slow.log找出新增的慢 SQL,再单独EXPLAIN它们 - 注意会话级干扰:
optimizer_switch='use_index_extensions=off'等配置可能让其他索引也“意外不可见”,建议用干净连接测试:mysql -u root -p --defaults-file=/dev/null
压测时发现性能没变化,其实是 use_invisible_indexes 没开
想对比“有/无该索引”的真实效果,却发现在压测中 QPS、延迟几乎一样——大概率是忘了打开 use_invisible_indexes 开关。默认它是 OFF,INVISIBLE 索引对优化器彻底隐身;不开它,你就永远测不到它“被启用”时的影响。
- 临时启用:
SET SESSION optimizer_switch='use_invisible_indexes=ON',然后跑EXPLAIN FORMAT=JSON看used_indexes - 千万别
SET GLOBAL,会影响所有新连接,生产环境禁用 - 备份恢复后,
mysqldump保留可见性,但xtrabackup不保证,上线前务必手动复查IS_VISIBLE字段
最常被忽略的一点:Invisible Index 不是“开关”,而是优化器的“选择性失明”——它物理存在、写入照常维护、唯一性检查照常执行,只是在生成执行计划前就被过滤掉了。验证它是否真正生效,永远要从 INFORMATION_SCHEMA 和 optimizer_switch 入手,而不是只盯 EXPLAIN 输出。


















