隐藏索引是mysql 8.0提供的元数据级“软禁”机制,仅修改is_visible标志、毫秒完成且不锁表,专用于安全验证删除索引的影响;主键及隐式主键不可设为不可见,否则报错error 3522。

它能让你在不删索引的前提下,真实验证“删了它会不会变慢”——对千万级表,这是唯一可落地的试错方式。
ALTER INDEX ... INVISIBLE 为什么是毫秒级且不锁表
因为这只是改 INFORMATION_SCHEMA.STATISTICS 表里的 IS_VISIBLE 字段,不碰 B+ 树结构、不重建索引页、不加元数据锁。对比 DROP INDEX:后者要重写整个索引,大表可能卡住写入数小时。
-
ALTER TABLE t ALTER INDEX idx_name INVISIBLE执行后立刻生效,SHOW INDEX FROM t \G中可见Visible: NO - 主键(含隐式主键)无法设为不可见,会报错
ERROR 3522 (HY000)或ER_PRIMARY_CANT_BE_INVISIBLE - 分区表上对某一分区设为不可见,其他分区不受影响;但执行
REORGANIZE PARTITION可能重置可见性
EXPLAIN 看不到隐藏索引?那怎么验证它到底有没有用
默认情况下优化器彻底忽略它,EXPLAIN 不显示、FORCE INDEX(idx_name) 会直接报错 ERROR 1176。必须临时启用才能测试:
- 会话级最安全:
SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ * FROM t WHERE ... - 全局开关
SET GLOBAL optimizer_switch = 'use_invisible_indexes=on'严禁在生产环境用 - 压测时只开这个开关还不够,得查
performance_schema.table_io_waits_summary_by_index_usage确认COUNT_STAR是否归零
隐藏索引不省空间、不减写开销,这点最容易误判
它只改优化器决策路径,不改物理维护行为:每次 INSERT/UPDATE/DELETE 仍会更新该索引的 B+ 树页,磁盘空间照占,写延迟照扣。想靠它“缓解负载”是典型误判。
- 备份恢复后可见性可能丢失:mysqldump 保留
INVISIBLE属性,xtrabackup 不保存,恢复后需手动查IS_VISIBLE列确认 - ORM 或应用代码里写了
USE INDEX(idx_name)的语句,设为不可见后会直接报错,上线前必须全量扫描代码和配置 - 观察周期建议 ≥24 小时,覆盖业务波峰波谷;期间异常只需一条
ALTER INDEX ... VISIBLE秒级回滚
真正难的是判断“它到底支不支撑关键路径”——不能只信单条 EXPLAIN,得盯慢日志、performance_schema 和真实 DML 延迟变化。一旦漏掉这些信号,就容易把救命索引当冗余给“藏没了”。











