不可见索引是让优化器彻底忽略而非临时隐藏,写入开销、唯一性校验和磁盘占用均照常;新建索引加INVISIBLE关键字,已有索引须用ALTER TABLE ... ALTER INDEX ... INVISIBLE切换,主键等特定索引不支持。

不可见索引不是“临时隐藏”,而是让优化器彻底忽略它——但写入开销、唯一性校验、磁盘占用全照常发生。直接删索引风险高,设为 INVISIBLE 是唯一能零重建成本验证影响的方式。
怎么创建或切换已有索引为不可见
新建索引时加 INVISIBLE 关键字即可;已有索引必须用 ALTER TABLE ... ALTER INDEX ... INVISIBLE 切换,其他语法(如 MODIFY INDEX)会报错。
CREATE INDEX idx_user_email ON users(email) INVISIBLE;ALTER TABLE users ADD INDEX idx_created_at (created_at) INVISIBLE;-
ALTER TABLE users ALTER INDEX idx_user_email INVISIBLE;✅ 唯一合法切换语法 - 主键、唯一约束依赖的索引、全文索引、空间索引不支持设为不可见
为什么 EXPLAIN 看不到不可见索引
这不是 bug,是设计行为:EXPLAIN 里压根不会列出不可见索引——优化器根本没把它纳入候选集。验证是否生效,得对比两种情况:
- 普通查询:
EXPLAIN SELECT * FROM users WHERE email = 'a@b.com';→ 若key字段为空或走了别的索引,说明它已被忽略 - 强制使用:
EXPLAIN SELECT * FROM users USE INDEX (idx_user_email) WHERE email = 'a@b.com';→ 若报Unknown index 'idx_user_email',说明索引名错了;若真走了该索引,证明它物理存在且可用 - 别信
SHOW INDEX FROM users的Comment字段(恒为NULL),查INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE或Visible列才准
如何判断这个索引到底有没有业务在用
不能只看 performance_schema.table_io_waits_summary_by_index_usage 里 COUNT_STAR = 0 就动手——低频关键查询(比如凌晨报表)可能一天只跑一次,但删了就崩。
- 切为不可见后,至少观察 24 小时,重点盯:
slow_query_log新增条目、Handler_read_next/Handler_read_rnd_next突增、应用层超时告警 - 想快速回滚?不用重建,一条
ALTER TABLE users ALTER INDEX idx_user_email VISIBLE;瞬间恢复 - 跨版本迁移含
INVISIBLE的表结构要小心:MySQL 5.7 及更低版本解析mysqldump输出会失败;--no-create-info手动建表会丢失可见性状态
真正容易被忽略的是:不可见索引仍参与唯一性校验和写入维护,所以即使你确认它“没被查询用”,也要检查是否有 INSERT/UPDATE 因它触发了唯一冲突或拖慢写入。观察 innodb_row_lock_waits 和慢写日志里的 INSERT ... ON DUPLICATE KEY UPDATE 类语句是否变多,比只盯读性能更关键。


















