MySQL 8.0 默认关闭 use_invisible_indexes,优化器完全忽略 invisible 索引,EXPLAIN 中不显示;需 SET SESSION optimizer_switch = 'use_invisible_indexes=on' 才使其参与执行计划生成。

能,但必须配合 optimizer_switch 和会话级控制,否则“无感知验证”根本不会发生——优化器默认完全忽略 invisible 索引,连 FORCE INDEX 都无效。
为什么直接建 INVISIBLE 索引后 EXPLAIN 看不到它
MySQL 8.0 默认关闭 use_invisible_indexes 开关,哪怕索引物理存在、SHOW INDEX 显示 Visible: NO,优化器也不会考虑它,更不会在 EXPLAIN 中出现。这不是 bug,是设计行为。
要让 invisible 索引参与执行计划生成,必须显式开启:
SET SESSION optimizer_switch = 'use_invisible_indexes=on';
注意:只对当前会话生效,不影响其他连接;全局设置需 SET GLOBAL,但不推荐在生产环境随意改全局配置。
- 该开关仅影响优化器是否“考虑”invisible索引,不影响索引维护(插入/更新/删除仍会同步写入)
- 即使开启,
FORCE INDEX(idx_name)对 invisible 索引依然报错:ERROR 1176 (HY000): Key 'idx_name' doesn't exist in table 'tbl' - 若用
USE INDEX或IGNORE INDEX,invisible 索引名会被直接忽略(不报错也不生效)
如何安全地对比 visible vs invisible 状态下的执行计划
核心是保持 SQL 完全一致,仅切换索引可见性 + 会话开关,避免缓存或统计信息干扰。
- 先确保目标索引当前是
VISIBLE,执行一次EXPLAIN FORMAT=TREE记录 baseline - 执行
ALTER TABLE tbl ALTER INDEX idx_name INVISIBLE;(8.0.12+ 是 instant DDL,但仍有短暂 MDL 锁) - 新开一个干净会话(避免继承旧 session 的
optimizer_switch),执行:SET SESSION optimizer_switch = 'use_invisible_indexes=on';<br>EXPLAIN FORMAT=TREE SELECT ... FROM tbl WHERE ...;
- 对比两份
EXPLAIN输出中的index、rows、filtered和实际执行耗时(用BENCHMARK()或慢日志采样) - 切回 visible 前,务必先关掉开关:
SET SESSION optimizer_switch = 'use_invisible_indexes=off';,否则可能误判
生产环境容易踩的三个坑
invisible 索引不是“开关灯”,它的副作用比想象中隐蔽。
-
mysqldump --no-data不导出INVISIBLE关键字,还原后索引自动变VISIBLE,导致备份恢复后行为突变 - 某些 ORM(如早期版本 Laravel Eloquent 或 Django ORM)在自动生成
SHOW INDEX元数据时,会跳过Visible: NO的索引,导致迁移脚本漏处理 - 监控工具(如 Percona PMM、Zabbix MySQL 模板)若依赖
information_schema.STATISTICS,默认不过滤Visible字段,可能把 invisible 索引误判为“高使用率冗余索引”并告警
什么时候不该用 invisible 索引做验证
它解决不了所有问题,强行套用反而引入风险。
- 主键、唯一约束依赖的索引(含隐式主键)不能设为 invisible —— 语句直接报错:
ERROR 3522 (HY000): Cannot alter visibility of an index that is used by a foreign key or primary key - 全文索引(
FULLTEXT)、空间索引(SPATIAL)不支持 invisible 属性,建表时加INVISIBLE会失败 - 如果查询本身走的是
range或ref类型且索引列基数极低(如性别字段),即使强制开启use_invisible_indexes,优化器也可能因成本估算过高而弃用,这时EXPLAIN看不到不代表索引无效,得看真实 QPS 和延迟分布
真正关键的不是“能不能切 invisible”,而是你是否清楚每个索引在哪些慢查里被实际用到、有没有被 ORDER BY / GROUP BY 隐式依赖、以及备份链路和监控链路是否兼容 invisible 属性——这些细节一旦漏掉,验证就从“无感知”变成“不可控”。











