不可见索引让优化器彻底忽略它,但写入开销、唯一性校验和磁盘占用仍存在;新建索引加invisible最稳妥,已有索引须用alter table ... alter index ... invisible切换,主键等特定索引不支持,explain默认不显示属设计行为,验证应以执行计划为准。

不可见索引不是“开关一按就停用”,而是让优化器彻底忽略它——但写入开销、唯一性校验、磁盘占用全在。直接删索引风险高,用 INVISIBLE 才是安全试错的正解。
怎么创建和切换 INVISIBLE 索引状态
新建索引时加 INVISIBLE 最稳妥;已有索引必须用 ALTER TABLE ... ALTER INDEX ... INVISIBLE 切换,其他语法(如 MODIFY INDEX)会报错。
-
CREATE INDEX idx_status ON orders(status) INVISIBLE;—— 新建即隐藏,无锁、秒级完成 -
ALTER TABLE orders ALTER INDEX idx_status INVISIBLE;—— 已有索引切换,只改元数据,不重建 B+ 树 - 主键、第一个
UNIQUE NOT NULL索引、FULLTEXT或SPATIAL索引不支持设为不可见,会触发ERROR 3522或ERROR 1214 - 即使
INVISIBLE,仍需获取元数据锁(MDL),高并发写入时可能短暂阻塞后续 DML
为什么 EXPLAIN 看不到 INVISIBLE 索引
这不是 bug,是设计行为:EXPLAIN 默认根本不会把不可见索引纳入候选集,所以 key 字段为空或走其他索引,属于正常现象。
- 验证是否生效,优先看执行计划:
EXPLAIN SELECT * FROM orders WHERE status = 'shipped';→ 若之前走idx_status,现在退化为type: ALL或换索引,才算隐藏成功 -
SHOW INDEX FROM orders中的Visible: NO是可靠信号,但Comment字段恒为NULL,别信它 -
SELECT IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS返回的是字符串'NO',不是布尔值;刚执行完ALTER可能有毫秒级延迟,建议以EXPLAIN结果为准 -
USE INDEX (idx_status)或FORCE INDEX (idx_status)会直接报错ERROR 1176: Key 'idx_status' doesn't exist—— 因为优化器默认“看不见”它
怎么临时启用 INVISIBLE 索引做 A/B 对比测试
想测“有/无该索引”对执行计划的真实影响,必须显式打开优化器开关,否则所有强制提示都无效。注意:MySQL 8.0.23+ 已移除 use_invisible_indexes 开关,旧版本也仅限会话级控制。
- 会话级启用(推荐):
SET SESSION optimizer_switch = 'use_invisible_indexes=on';,然后跑EXPLAIN;两次EXPLAIN必须在同一 session 下,且确认没被其他optimizer_switch设置干扰 - SQL 级启用(更安全):
SELECT /*+ SET_VAR(optimizer_switch = 'use_invisible_indexes=on') */ * FROM orders WHERE status = 'shipped';,再EXPLAIN,避免污染会话状态 - 启用后,
FORCE INDEX (idx_status)就能成功走索引;关闭后立刻失效——这才是验证“是否真被忽略”的黄金标准 - 别依赖全局配置,线上环境无法统一管控;ORM 自动生成的 SQL 中硬编码提示容易被覆盖,慎用
观察期要盯什么指标才不算白测
切为 INVISIBLE 后不能只等慢查询日志,很多问题藏在底层指标里。24 小时是底线,关键业务建议观察 3–7 天。
- 查
performance_schema.table_io_waits_summary_by_index_usage:若COUNT_STAR = 0是基础参考,但低频关键查询可能漏掉 - 盯
Handler_read_next、Handler_read_rnd_next是否突增——说明从索引扫描退化为全表扫描或文件排序 - 慢查询日志里
Rows_examined显著升高,或出现新Using filesort/Using temporary提示 -
INVISIBLE索引仍参与唯一性校验:哪怕隐藏,INSERT触发重复键仍会报ERROR 1062;它也持续消耗磁盘空间和写入性能 - 长期挂着
INVISIBLE索引是埋雷:备份恢复时若用mysqldump --no-create-info+ 手动建表,INVISIBLE属性会丢失











