不可见索引是让优化器默认忽略而非隐藏,唯一合法语法是alter table t1 alter index idx_name invisible;主键、外键依赖索引等硬性禁止设为不可见,验证必须查information_schema.statistics.is_visible=no。

不可见索引不是“隐藏起来看不见”,而是让优化器默认忽略它——ALTER TABLE ... ALTER INDEX ... INVISIBLE 是唯一合法方式,写错语法会直接报错,且主键、唯一约束索引根本不能设为不可见。
怎么用 ALTER TABLE ALTER INDEX 切换可见性
必须用标准语法,任何变体都会失败:
-
ALTER TABLE t1 ALTER INDEX idx_name INVISIBLE;—— 正确,毫秒级元数据变更 -
ALTER TABLE t1 ALTER INDEX idx_name VISIBLE;—— 恢复时也必须这么写 - 写成
SET INVISIBLE、MODIFY INDEX idx_name INVISIBLE或CHANGE INDEX全部报错ERROR 1064 (42000) - 操作只改
INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE字段,不重建表、不锁数据行,但需短暂持有元数据锁(MDL),长事务未提交时会被阻塞
哪些索引不能设为 INVISIBLE
MySQL 在解析阶段就硬拦截,不会走到执行层:
- 主键索引(包括显式
PRIMARY KEY和隐式主键,如UNIQUE NOT NULL列)——报错ERROR 3522 (HY000): Primary key cannot be invisible - 被外键约束直接引用的索引
- 唯一约束(
UNIQUE KEY)本身可以设为不可见,但若该列同时是外键或被其他约束依赖,切换前需人工确认逻辑一致性 - 全文索引、空间索引、MyISAM 表索引——全部不支持
怎么验证 INVISIBLE 是否生效
SHOW INDEX FROM t1 的 Comment 字段恒为 NULL,不能信;Visible 列在 MySQL 8.0.12+ 才有,且部分旧脚本会漏掉它:
- 唯一可靠方式是查
INFORMATION_SCHEMA.STATISTICS:SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1' AND INDEX_NAME = 'idx_name'; - 返回
NO才算成功;YES表示当前可用 - 用
EXPLAIN SELECT ...看执行计划:不可见索引不会出现在key字段里,也不会进possible_keys列表——这是正常行为,不是 bug - 想临时走这个索引,只能用
USE INDEX (idx_name)或先开会话级开关:SET SESSION optimizer_switch = 'use_invisible_indexes=on';
FORCE INDEX 为什么“失效”了
这不是失效,是设计如此:FORCE INDEX 无法穿透优化器对 IS_VISIBLE = NO 的过滤层:
-
SELECT * FROM t1 FORCE INDEX (idx_j) WHERE j = 10;会静默降级——不报错、不警告、也不走idx_j,可能退到全表扫描 - 而
USE INDEX (idx_j)会强制使用,但如果idx_j根本不存在,会报ERROR 1176 (42000): Key 'idx_j' doesn't exist - 灰度测试前必须全局扫代码、ORM 配置、存储过程,移除所有
FORCE INDEX和USE INDEX,否则观察结果失真 - 备份还原后行为可能突变:
mysqldump --no-data不导出INVISIBLE关键字,还原后索引自动变回VISIBLE
真正容易被忽略的是:不可见索引本身不提升性能,它的价值全在“可逆性”——切完立刻生效,切错立刻回滚,但前提是别忘了检查 INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE,而不是只看 SHOW INDEX。











