invisible索引用于安全验证索引性能影响,通过“屏蔽—观察—决策”闭环降低删索引风险;仅修改元数据、不锁表、不重建b+树,但写入仍维护;主键不可设为不可见,force index对其无效,需开启use_invisible_indexes开关压测。

INVISIBLE 索引不是为了“让查询变快”,而是为了安全验证某个索引是否真能提升查询性能——它把“删索引”这个高风险操作,拆成了“先屏蔽、再观察、后决定”的三步闭环。
ALTER TABLE ALTER INDEX INVISIBLE 是元数据操作,不改数据也不锁表
执行 ALTER TABLE t1 ALTER INDEX idx_name INVISIBLE 仅修改 information_schema.STATISTICS 表里的 Visible 字段,耗时毫秒级。它不重建 B+ 树、不阻塞 DML、不释放磁盘空间。
- 主键索引(含隐式主键)强制禁止设为
INVISIBLE,会报错ERROR 3522 (HY000): Primary key cannot be invisible - 唯一约束索引可以设为不可见,但
INSERT/UPDATE仍会检查该约束,失败逻辑不变 -
SHOW INDEX FROM t1仍显示该索引,只是Visible列值为NO
FORCE INDEX 对 INVISIBLE 索引完全无效
哪怕你写 SELECT * FROM t1 FORCE INDEX (idx_name) WHERE ...,只要 idx_name 是 INVISIBLE,MySQL 就直接报错:ERROR 1176 (42000): Key 'idx_name' doesn't exist in table 't1' —— 它不是“忽略”,而是“在解析阶段就认定不存在”。
- 优化器在生成执行计划前,已过滤掉所有
Visible = NO的索引,FORCE无法绕过这层校验 - 验证方式必须是查
information_schema.statistics,不能只看EXPLAIN输出 - ORM 或中间件里硬编码的
FORCE INDEX必须提前清理,否则上线即故障
use_invisible_indexes 开关才是压测关键
默认情况下,optimizer_switch='use_invisible_indexes=OFF',所以 INVISIBLE 索引对优化器彻底隐身。但压测时你需要反向打开它,才能对比“有/无该索引”的真实效果:
- 临时启用:执行
SET SESSION optimizer_switch='use_invisible_indexes=ON' - 然后跑
EXPLAIN FORMAT=JSON,重点看used_indexes和key字段是否出现目标索引 - 全局设置
SET GLOBAL会影响所有新连接,生产环境禁用 - 备份恢复后,
mysqldump保留可见性,但xtrabackup不保证,需手动复查
长期挂着 INVISIBLE 索引反而拖慢写入
很多人误以为“看不见=不维护”,其实相反:INVISIBLE 索引在 INSERT/UPDATE/DELETE 时照常更新 B+ 树页、占用 buffer pool、产生 redo log —— 它只省掉了“被选中”的那一步。
- 写入延迟不会下降,磁盘空间不会释放,唯一节省的是优化器决策开销
- 分区表上某一分区的索引设为不可见,
REORGANIZE PARTITION可能重置其状态 - 如果观察期(比如一周慢查日志 + QPS/RT 监控)确认无影响,就该
DROP INDEX,别留着占地方
真正容易被忽略的一点:不可见索引的价值不在“技术实现多巧妙”,而在于它把一个需要停机、需要回滚、需要紧急重建的运维动作,压缩成一条瞬时 SQL 和一次业务侧可观测的验证周期。一旦你开始依赖它做索引治理,就要同步建立配套机制——比如定期扫描 information_schema.STATISTICS 里 Visible = NO 且 INDEX_TYPE = 'BTREE' 的索引,标记超期未决策项。











