invisible索引仅让优化器忽略它,不优化ddl但保障ddl安全;设为不可见或可见须用alter table ... alter index ... invisible/visible;主键及唯一约束索引不可设为不可见;force index对不可见索引无效,use index或启用use_invisible_indexes方可强制使用。

INVISIBLE 索引本身不优化 DDL,它只是让优化器忽略索引——但正因为这个“忽略”,你才能安全做 DDL 决策,避免误删关键索引导致查询雪崩。
ALTER TABLE ALTER INDEX INVISIBLE 是唯一合法语法
想把已有索引设为不可见,必须用:ALTER TABLE t1 ALTER INDEX idx_name INVISIBLE;。写成 SET INVISIBLE、MODIFY INDEX 或 CHANGE INDEX 全都会报错 ERROR 1064 (42000)。切换回可见也一样:ALTER TABLE t1 ALTER INDEX idx_name VISIBLE;。这两个操作都是元数据级瞬时变更,不重建表、不锁表(仅需短暂元数据锁),毫秒完成。
主键和唯一约束索引不能设为不可见
这是硬限制,不是配置问题:PRIMARY KEY、隐式主键(如 UNIQUE NOT NULL 列)、以及被外键或唯一约束直接依赖的索引,执行 ALTER INDEX ... INVISIBLE 会立刻失败,报错 ERROR 3522 (HY000): Primary key cannot be invisible。别试图绕过——MySQL 在解析阶段就拒绝,不会走到执行层。
FORCE INDEX 对 INVISIBLE 索引无效,但 USE INDEX 可以
这是最常踩的坑:SELECT * FROM t1 FORCE INDEX (idx_j) WHERE j = 10; 不会走 idx_j,哪怕它物理存在且状态是 INVISIBLE。优化器在生成执行计划前就过滤掉了所有 IS_VISIBLE = NO 的索引,FORCE 无法穿透这层过滤。真正能临时启用它的,只有两种方式:
-
SELECT * FROM t1 USE INDEX (idx_j) WHERE j = 10;(语句级强制) -
SET SESSION optimizer_switch = 'use_invisible_indexes=on';后再执行普通查询(会话级开关)
注意:USE INDEX 若指向一个根本不存在的索引名,会报 ERROR 1176 (42000): Key 'xxx' doesn't exist;而 FORCE INDEX 遇到不可见索引则静默降级,不报错也不警告,容易误判。
验证状态别信 SHOW INDEX 的 Comment 字段
SHOW INDEX FROM t1\G 输出里的 Comment 字段恒为 NULL,它不反映可见性。真正可靠的检查方式是查 INFORMATION_SCHEMA.STATISTICS:
SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1' AND INDEX_NAME = 'idx_j';
返回 NO 才表示设置成功。另外,SHOW INDEX 在 MySQL 8.0.12+ 中新增了 Visible 列,但很多运维脚本或旧版客户端硬编码列顺序,会漏掉它——所以别依赖显示,只信 IS_VISIBLE 值。
真正难的是判断“这个索引到底能不能删”。INVISIBLE 只帮你停用功能,但它仍占磁盘、拖慢写入、做唯一性校验。你得结合 performance_schema.table_io_waits_summary_by_index_usage 观察真实命中率,再配上线上的慢日志聚合分析——否则很容易把“没被优化器选中”当成“完全没用”。











