MySQL 8.0 中不可见索引仅支持 ALTER TABLE ... ALTER INDEX ... INVISIBLE,秒级生效且不重建表;主键及唯一约束索引不可设为不可见;需查 INFORMATION_SCHEMA.STATISTICS 确认 IS_VISIBLE=NO;FORCE INDEX 会绕过可见性检查;备份工具行为、分区表 DDL 和应用层提示需提前对齐。

ALTER TABLE ... ALTER INDEX ... INVISIBLE 是 MySQL 8.0 实现不可见索引的唯一标准方式,不是 SET INVISIBLE(该语法不存在)。它不删除索引,也不重建表,只改元数据,秒级生效。
怎么正确执行不可见索引切换
必须用 ALTER TABLE tbl_name ALTER INDEX idx_name INVISIBLE,不能写成 SET INVISIBLE 或 MODIFY INDEX ... INVISIBLE —— 后两者会报错 ERROR 1064 (42000)。
-
INVISIBLE和VISIBLE是互斥操作,切换时无需先DROP或REBUILD - 仅支持 InnoDB 表;MyISAM 不支持该特性
- 主键索引、唯一约束依赖的索引强制拒绝设为不可见,报错
ERROR 3522 (HY000) - 执行后立即生效,但需注意:长事务未提交时,
ALTER会被阻塞在元数据锁(MDL)等待阶段
为什么 SHOW INDEX 看不到 Visible 列
MySQL 5.7 及更早版本的 SHOW INDEX 输出里没有 Visible 字段。即使你在 MySQL 8.0 上执行了 ALTER INDEX ... INVISIBLE,旧版客户端或某些 ORM 工具调用 SHOW INDEX 仍可能忽略可见性状态。
- 真正可靠的检查方式是查
INFORMATION_SCHEMA.STATISTICS表:SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't1' AND INDEX_NAME = 'idx_name' -
IS_VISIBLE值为NO才表示设置成功,YES表示当前可用 -
SHOW INDEX FROM t1在 MySQL 8.0+ 中已扩展字段,但部分运维脚本硬编码列序,可能漏掉新增的Visible列
FORCE INDEX 为什么还能走不可见索引
FORCE INDEX 是优化器的硬指令,它绕过索引可见性检查逻辑。一旦 SQL 中写了 FORCE INDEX(idx_name),哪怕该索引是 INVISIBLE,也会被强制使用,并可能触发 ERROR 1176 (42000): Key 'idx_name' doesn't exist in table 't1' —— 这说明索引虽存在,但优化器在常规路径下已将其“注销”。
- 灰度测试前必须全局扫描代码、ORM 配置、存储过程,移除所有
FORCE INDEX和USE INDEX - 备份恢复后行为可能突变:mysqldump 默认不导出
INVISIBLE关键字,还原后索引变回VISIBLE;xtrabackup 物理备份则保留元数据,但需确认版本兼容性 - 分区表上对单个分区设不可见,
ALTER TABLE ... REORGANIZE PARTITION可能重置所有分区索引可见性,需事后复查
压测时 optimizer_switch 必须手动控制
MySQL 默认关闭 use_invisible_indexes 开关,所以 INVISIBLE 索引真“不可见”。但验证“如果启用它,计划会不会更好”,就得临时打开:
- 只对当前 session 生效:
SET SESSION optimizer_switch='use_invisible_indexes=on'; - 之后再跑
EXPLAIN FORMAT=JSON SELECT ...,看used_indexes是否包含该索引名 - 切记别用
SET GLOBAL,否则所有新连接都会考虑不可见索引,线上可能引发计划突变 -
EXPLAIN ANALYZE比EXPLAIN更准,能实际执行并反馈是否真走了该索引


















