INVISIBLE索引是为删改索引提供可回滚的安全阀:毫秒级修改元数据、不锁表、不重建B+树,仅让优化器默认忽略;必须用ALTER TABLE ... ALTER INDEX ... INVISIBLE语法,主键或首个唯一索引设为不可见会报ERROR 3522。

INVISIBLE 索引不是用来加速查询的,而是给索引删改操作加一层“可回滚的安全阀”——千万级表上想删一个疑似冗余的索引?直接 DROP INDEX 可能引发慢查询雪崩;而设为 INVISIBLE 是毫秒级元数据翻转,不锁表、不重建、不中断业务,只让优化器默认绕开它。
怎么安全地把一个已有索引设为不可见
必须用完整 ALTER TABLE ... ALTER INDEX ... INVISIBLE 语法,其他写法全报错:ERROR 1064 (42000)。
-
ALTER TABLE users ALTER INDEX idx_email INVISIBLE;✅ 正确,仅改INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE字段 -
ALTER INDEX idx_email INVISIBLE ON users;❌ 报错,MySQL 8.0 不支持这种语法糖 -
SET INVISIBLE idx_email;❌ 不存在该语句
执行前先确认它不是主键或外键依赖索引:
SELECT CONSTRAINT_TYPE FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'users' AND COLUMN_NAME = 'email';
若返回 PRIMARY KEY 或 UNIQUE 且是首个非空唯一列,ALTER 会触发 ERROR 3522。
为什么 EXPLAIN 看不到它,但又不能信 SHOW INDEX
EXPLAIN 默认完全忽略 IS_VISIBLE = 'NO' 的索引,这是设计行为,不是 bug。你看到 key: NULL 或走了别的索引,恰恰说明它真被跳过了。
- 别信
SHOW INDEX FROM users\G的Visible: NO就完事——这个字段可能有毫秒级延迟,且Comment恒为NULL - 查系统表才准:
SELECT IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'users' AND INDEX_NAME = 'idx_email';,返回字符串'NO'才算生效 - 如果
EXPLAIN还走这个索引,大概率是当前会话开了use_invisible_indexes=on:运行SELECT @@optimizer_switch LIKE '%use_invisible_indexes=on%';确认,再用SET SESSION optimizer_switch = 'use_invisible_indexes=off';关掉
FORCE INDEX(idx_name) 报错 ERROR 1176 怎么办
这不是故障,是预期行为:FORCE INDEX 要求索引逻辑可见;一旦设为 INVISIBLE,优化器在解析阶段就把它“注销”了,所以 ERROR 1176 (HY000): Key 'idx_name' doesn't exist 是必然结果。
- ORM 层(如 MyBatis 的
@SelectKey、Django 的extra())若硬编码了USE INDEX或FORCE INDEX,上线后会直接失败,必须提前全量扫描代码和 SQL 配置 - 临时验证影响,只能用会话级开关:
SET SESSION optimizer_switch = 'use_invisible_indexes=on';,再跑EXPLAIN对比;更安全的是 SQL 级:SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ * FROM users WHERE email = 'a@b.com'; - 注意:全局开关
SET GLOBAL optimizer_switch = 'use_invisible_indexes=on'严禁在生产环境启用,会影响所有会话
灰度观察时最容易漏掉的三个信号
设成 INVISIBLE 后,不能只看单条 EXPLAIN 是否退化——真实影响藏在慢日志、IO 统计和 DML 延迟里。
- 盯
performance_schema.table_io_waits_summary_by_index_usage:确认该索引的COUNT_STAR归零,否则说明仍有查询在隐式命中(比如某些 ORM 自动生成的 hint) - 查慢日志:对比开启前后 24 小时内新增的慢查询,尤其关注原来走该索引、现在变成全表扫描的 SQL 模板
- 监控 DML 延迟:虽然
INVISIBLE不省写入开销,但如果某条UPDATE突然变慢,可能是它原本依赖该索引做快速定位,现在被迫走主键回表或扫描
真正卡点不在“怎么设”,而在“怎么确认它真没被关键路径依赖”——哪怕只有一条高频更新语句靠它提速,藏错索引就是埋雷。


















