不可见索引是让优化器忽略但不删除的索引,仍占用空间并参与写入维护;主键和唯一约束索引不可设为不可见;验证需用use_invisible_indexes开关闭环测试;长期挂载无用索引会增加系统负担,应依据监控数据果断删除。

不可见索引不是“删不了”,而是“先不让你用”
MySQL 8.0 的 INVISIBLE 索引本质是让优化器在生成执行计划时忽略该索引,但索引结构、数据维护、B+树更新全部照常进行。它不解决磁盘空间或写入开销问题,只解决“能不能被选中”这个决策层问题。
典型误判是以为设成 INVISIBLE 就能降低写入延迟——实际不会。因为 INSERT/UPDATE/DELETE 仍要同步更新该索引页,只是 SELECT 不会走它。
- 主键索引(含隐式主键)无法设为
INVISIBLE,尝试会报错ERROR 3522 (HY000): A primary key index cannot be invisible - 唯一约束依赖的索引若被设为不可见,INSERT/UPDATE 可能因违反唯一性而失败,即使索引不可见,约束检查仍生效
-
SHOW INDEX FROM tbl仍显示该索引,Visible列值为NO,这是唯一直观标识
压测时怎么验证“去掉这个索引会不会变慢”
核心思路:不动表结构、不重建索引、不改应用代码,只控制优化器行为。关键靠两步闭环验证:
- 先用
ALTER TABLE t1 ALTER INDEX idx_name INVISIBLE把索引设为不可见 - 在压测客户端连接后,临时打开
use_invisible_indexes=ON:执行SET SESSION optimizer_switch='use_invisible_indexes=ON',再跑EXPLAIN或真实 SQL,确认执行计划是否真的回退到没索引的状态 - 对比开启/关闭该开关下的
EXPLAIN FORMAT=JSON输出,重点看used_indexes和key字段是否消失 - 注意:全局开关
SET GLOBAL optimizer_switch会影响所有新会话,生产环境慎用;压测建议只对当前 session 生效
平滑下线索引必须绕开的三个坑
很多人把 INVISIBLE 当成“删除前的安全阀”,但实际落地时容易卡在以下环节:
- 应用里写了
FORCE INDEX(idx_name)—— 这种显式强制会无视INVISIBLE属性,直接报错ERROR 1176 (42000): Key 'idx_name' doesn't exist in table 't1',必须提前扫描代码/ORM 配置移除所有FORCE/USE提示 - 备份恢复后索引仍是
INVISIBLE状态,mysqldump 默认导出可见性属性,但某些物理备份工具(如 xtrabackup)不保留该元数据,恢复后可能意外变回VISIBLE - 分区表上对某个分区的索引设为不可见,其他分区不受影响;但
ALTER TABLE ... REORGANIZE PARTITION操作可能重置所有分区索引可见性,需事后复查
什么时候该删,而不是一直挂着 invisible
不可见索引仍占用磁盘、消耗写入资源、增加 buffer pool 压力。长期挂着只是“假装安全”,真正该删的信号很明确:
- 连续 7 天压测 + 线上流量观察,
slow_query_log中无任何语句因缺失该索引导致Using filesort或全表扫描 -
information_schema.INNODB_METRICS中index_page_splits和index_page_reorgs对应该索引的计数持续为 0 - 监控发现该索引的
Handler_read_next/Handler_read_prev值在设为INVISIBLE后归零,且不再回升
删之前最后执行一次 ALTER TABLE t1 DROP INDEX idx_name,别留着“以防万一”——看不见的索引,最容易被遗忘在监控盲区里。











