不可见索引本身不优化查询,仅让优化器忽略该索引以实现安全试错;alter table alter index invisible是瞬时元数据操作,只修改information_schema.statistics的is_visible字段,不重建索引、不锁表、毫秒完成,但主键等特定索引禁止设为不可见,force index对其无效。

不可见索引本身不优化查询,它只让优化器“看不见”某个索引——所以你不能靠它提速,但能靠它安全试错、避免锁表重建。
ALTER TABLE ALTER INDEX INVISIBLE 为什么是瞬时操作
这个语句只修改 information_schema.STATISTICS 表里的 Visible 字段,不触碰数据页、不重建B+树、不加写锁(仅需元数据锁 MDL,且持续时间极短)。对大表来说,ALTER TABLE t ALTER INDEX idx_name INVISIBLE 几乎毫秒完成,业务查询完全不受影响。
- 主键索引、全文索引、空间索引、被外键或唯一约束强依赖的索引,不允许设为不可见,执行会直接报错
ERROR 3522 (HY000): Primary key cannot be invisible - 8.0.12+ 支持 instant DDL,但高并发写入场景下仍可能短暂阻塞 MDL,建议避开流量高峰执行
- 切换后索引物理结构不变,写入开销、磁盘占用、唯一性校验照常进行——它只是“隐身”,不是“休眠”
FORCE INDEX 或 USE INDEX 对不可见索引无效
这是最容易误判的点:即使你写了 FORCE INDEX (idx_name),只要该索引是 INVISIBLE,MySQL 在生成执行计划前就把它过滤掉了,不会报错,也不会警告,只会退回到全表扫描或其它可用索引。
- 验证方式:用
EXPLAIN SELECT * FROM t USE INDEX (idx_name) WHERE ...—— 如果报错Unknown index 'idx_name',说明索引名错了;如果走了该索引,说明它物理存在且当前可见 - 真正想强制用不可见索引?得临时打开会话级开关:
SET optimizer_switch = 'use_invisible_indexes=on';,但这非常规操作,仅用于调试 -
SHOW INDEX FROM t的Comment字段恒为 NULL,别信它;要看Visible列,或查SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS
怎么判断一个索引是否真没被用,再决定设为不可见
不能光看 performance_schema.table_io_waits_summary_by_index_usage 里 COUNT_STAR = 0 就动手——低频但关键的查询(比如凌晨报表、风控拦截)可能漏统计。
- 先查慢查询日志里有没有依赖该索引的语句:
SELECT * FROM mysql.slow_log WHERE argument LIKE '%WHERE col = %' AND start_time > DATE_SUB(NOW(), INTERVAL 7 DAY); - 观察切换前后
Handler_read_next、Handler_read_rnd_next是否突增,这是全表扫描加重的信号 - 应用层监控是否有超时告警、P99响应时间跳变,比数据库指标更贴近真实影响
- 设为不可见后至少观察 24 小时,尤其覆盖业务高峰和定时任务窗口
最易被忽略的是跨版本兼容问题:含 INVISIBLE 的建表语句或 mysqldump 输出,在 MySQL 5.7 或更低版本里会解析失败;用 --no-create-info 导出再手动建表,也会丢失可见性状态。线上环境若存在多版本混用,切记提前校验。











