mysql 8.0+ 的 invisible index 是让优化器默认忽略但不删除的索引,需用 invisible 关键字创建或通过 alter table alter index 切换可见性,仅支持 innodb 表,不影响物理结构但影响工具链行为。

MySQL 8.0+ 怎么创建 Invisible Index
不可见索引不是“隐藏”或“删除”,而是让优化器默认忽略它——除非你显式强制使用。必须用 INVISIBLE 关键字声明,且仅支持 InnoDB 表。
-
CREATE INDEX idx_name ON tbl(col) INVISIBLE;—— 创建时直接设为不可见 -
ALTER TABLE tbl ALTER INDEX idx_name INVISIBLE;—— 已有索引可在线切换可见性(MySQL 8.0.23+ 支持) -
ALTER TABLE tbl ALTER INDEX idx_name VISIBLE;—— 恢复可见,优化器立刻能用 - 不支持全文索引、空间索引、主键、唯一约束依赖的索引设为不可见
执行计划里看不见 Invisible Index 是正常现象
只要没加 USE INDEX 或 FORCE INDEX,EXPLAIN 结果里就不会出现它——这不是 bug,是设计行为。优化器压根不把它纳入候选集。
- 错误预期:“加了 INVISIBLE 就该在 EXPLAIN 里灰掉显示” → 实际是彻底不列出来
- 验证是否生效:先
EXPLAIN SELECT * FROM tbl WHERE col = ?;,再EXPLAIN SELECT * FROM tbl USE INDEX(idx_name) WHERE col = ?;,后者应走该索引 -
information_schema.statistics中INDEX_COMMENT字段为空,但IS_VISIBLE列值为NO
ALTER TABLE ... ALTER INDEX 会锁表吗
取决于 MySQL 版本和操作类型。8.0.12 起 ALTER INDEX ... INVISIBLE/VISIBLE 是 instant DDL(无拷表),但仍有元数据锁(MDL)短时等待。
- 8.0.12–8.0.22:instant,不重建表,但需等待正在执行的查询释放 MDL
- 8.0.23+:支持并发 DML,锁粒度更细,但仍可能阻塞新事务的 DDL 请求
- 别在高峰期批量切几十个索引可见性,容易堆积 MDL 等待
- 注意:
ALTER TABLE ... ADD INDEX ... INVISIBLE仍是 inplace,但耗时与建索引本身一致
为什么 DROP INDEX 前要先设成 VISIBLE
不是必须,但强烈建议。因为某些客户端工具、备份恢复流程或 ORM(如旧版 Laravel Schema Builder)会扫描 SHOW INDEXES 并假设所有索引都参与查询优化,若遇到不可见索引可能报错或跳过处理。
- Percona Toolkit 的
pt-online-schema-change在检测索引一致性时,可能把 INVISIBLE 索引误判为“缺失” -
mysqldump --no-data 默认导出所有索引定义,但不带
INVISIBLE关键字,还原后变成 visible,行为突变 - 最稳妥做法:
ALTER INDEX idx_name VISIBLE;→ 确认业务无影响 → 再DROP INDEX
MySQL 的 Invisible Index 是个轻量级灰度开关,但它不改变索引物理结构,也不降低维护开销——写放大、空间占用、二级索引更新延迟全照旧。真正容易被忽略的是:它对复制、备份、监控工具的影响,往往比对查询计划的影响更隐蔽。











