不可见索引不是删不掉的索引,而是先不让优化器用的索引,专为解决删索引前不敢试、试了怕回不来的问题;它仅修改元数据is_visible字段,毫秒完成、不锁表、不重建b+树,主键及隐式主键不可设为不可见。

不可见索引不是“删不掉的索引”,而是“先不让优化器用”的索引——它唯一解决的问题是:删索引前,你不敢试,试了又怕回不来。
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 - 主键(含隐式主键)强制不允许设为
INVISIBLE,否则报错ERROR 3522或ER_PRIMARY_CANT_BE_INVISIBLE - 分区表上对某一分区设为不可见,其他分区不受影响;但执行
REORGANIZE PARTITION可能重置整个表的可见性
EXPLAIN 看不到隐藏索引?怎么验证它到底有没有用
默认情况下优化器彻底忽略不可见索引:EXPLAIN 不显示、FORCE INDEX(idx_name) 会直接报错 ERROR 1176 (HY000): Key 'xxx' doesn't exist。必须临时启用才能测试:
- 会话级最安全:
SET SESSION optimizer_switch = 'use_invisible_indexes=on';,再跑目标 SQL 的EXPLAIN FORMAT=JSON,检查used_indexes和key字段是否命中该索引名 - 单条 SQL 级别更精准:
SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ * FROM t WHERE ... - 全局开关
SET GLOBAL严禁在生产环境用,会污染所有新会话
备份恢复后不可见状态可能丢失,这点最容易被忽略
mysqldump 默认保留 INVISIBLE 属性,但物理备份工具(如 xtrabackup)不保存该元数据。恢复后索引可能意外变回 VISIBLE,导致压测结论完全失效。
- 上线前务必确认:
SELECT IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA='db' AND TABLE_NAME='t' AND INDEX_NAME='idx_name'; - ORM 或应用代码里写了
USE INDEX(idx_name)或硬编码FORCE INDEX的语句,设为不可见后会直接报错,上线前必须全量扫描代码和配置 - 不可见索引仍参与写入维护:
INSERT/UPDATE/DELETE一样更新 B+ 树页,不会降低写延迟——它只回答“要不要用”,不回答“要不要存”
真正难的是判断“它到底支不支撑关键路径”:不能只信单条 EXPLAIN,得盯慢日志、performance_schema.table_io_waits_summary_by_index_usage 的 COUNT_STAR 是否归零,以及真实 DML 延迟变化。漏掉这些信号,就容易把救命索引当冗余给“藏没了”。











