不可见索引使优化器彻底无视它,但写入开销、磁盘占用和唯一性校验仍存在;创建时加INVISIBLE关键字,切换需用ALTER TABLE...ALTER INDEX...INVISIBLE;主键等特定索引不支持;EXPLAIN不显示,验证需强制USE INDEX;测试删除影响宜先设为不可见并观察24小时。

直接说结论:不可见索引不是“隐藏界面”,而是让优化器彻底无视它——除非你显式强制或打开会话开关。它不参与 EXPLAIN,不进执行计划,但写入开销、磁盘占用、唯一性校验全在。
怎么创建和切换 INVISIBLE 索引状态
新建索引时加 INVISIBLE 关键字,已有索引用 ALTER TABLE ... ALTER INDEX ... INVISIBLE 切换。注意:
-
CREATE INDEX idx_name ON t(col) INVISIBLE;和ALTER TABLE t ADD INDEX idx_name (col) INVISIBLE;都合法 - 已有索引切换必须用
ALTER TABLE t ALTER INDEX idx_name INVISIBLE;,不能写成MODIFY INDEX或CHANGE INDEX - 主键、唯一约束依赖的索引(包括隐式主键)、全文索引、空间索引不支持设为不可见
- 8.0.12+ 支持 instant DDL,但仍有元数据锁(MDL),高并发写入时可能短暂阻塞
为什么 EXPLAIN 看不到 INVISIBLE 索引
这不是 bug,是设计行为:EXPLAIN 里压根不会列出不可见索引——优化器根本没把它纳入候选集。验证是否生效,得对比两种情况:
- 普通查询:
EXPLAIN SELECT * FROM t WHERE col = 1;→key字段为空或走其他索引 - 强制使用:
EXPLAIN SELECT * FROM t USE INDEX (idx_name) WHERE col = 1;→ 若报错Unknown index 'idx_name',说明索引名错了;若走了该索引,说明它物理存在且可用 - 别信
SHOW INDEX FROM t的Comment字段(它恒为NULL),要看Visible列(8.0.12+)或查INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE
怎么安全测试删除索引的真实影响
核心思路是「停用功能,保留结构」,避免重建成本。实操要点:
- 先确认索引当前是否被用:
SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage WHERE OBJECT_SCHEMA = 'db' AND OBJECT_NAME = 't' AND INDEX_NAME = 'idx_name';,COUNT_STAR = 0是基础参考,但不是绝对依据(比如低频关键查询) - 切为不可见后,观察至少 24 小时:重点盯慢查询日志、
Handler_read_*指标突增、应用层超时告警 - 想临时“回滚”测试?不用等重建,一条
ALTER TABLE t ALTER INDEX idx_name VISIBLE;瞬间生效 - 切勿跨版本迁移含
INVISIBLE的表结构:5.7 或更低版本解析mysqldump输出会失败;--no-create-info手动建表会丢失可见性
容易被忽略的副作用和权限坑
INVISIBLE 索引不是“静默旁观者”,它仍在后台干活:
- 写入性能照拖:INSERT/UPDATE/DELETE 仍要维护该索引 B+ 树,磁盘 I/O 和缓冲池压力不变
- 唯一约束照判:UNIQUE INVISIBLE 索引依然会拦截重复值,报
Duplicate entry错误 - 备份还原需留意:
mysqldump默认导出/*!80000 INVISIBLE */注释,但某些 ORM(如旧版 Laravel)或巡检脚本可能忽略该标记,误判为“有效索引” - 权限只要
INDEX,不需要ALTER全权限,但部分 DBA 工具(如 pt-online-schema-change)可能因识别不到可见性而报“索引不一致”
真正难的从来不是切状态,而是判断“这个索引到底有没有人用”。performance_schema 数据重启即丢,sys.schema_unused_indexes 只能看历史,INVISIBLE 提供的是一个可控的干预窗口——但窗口开着的时候,写入成本一分不少,这点常被低估。



















