不可见索引不能加速查询,而是为安全验证索引影响提供灰度能力;alter table ... alter index invisible仅修改元数据、毫秒完成、不锁表、不重建b+树,而drop index需全量重建、可能阻塞写入数小时,且主键等特定索引禁止设为不可见。

不可见索引不能加速查询,但能让 DROP INDEX 这种高危 DDL 变得可灰度、可回滚、不锁表。
ALTER TABLE ... ALTER INDEX INVISIBLE 为什么比 DROP INDEX 安全得多
DROP INDEX 需要重建整个 B+ 树结构,对千万级表可能阻塞写入数小时;而 ALTER TABLE t ALTER INDEX idx_name INVISIBLE 只修改 INFORMATION_SCHEMA.STATISTICS.IS_VISIBLE 字段,毫秒完成,业务无感。它不释放磁盘空间、不降低写入开销、不跳过唯一性校验——只是让优化器“假装没看见”。
- 主键(含隐式主键)、外键依赖的唯一索引、全文索引、空间索引禁止设为不可见,执行直接报错
ERROR 3522 (HY000): Primary key cannot be invisible - 分区表上设为不可见只影响当前分区,但
REORGANIZE PARTITION可能重置可见性 - 物理备份(如
xtrabackup)不保留IS_VISIBLE状态,恢复后索引自动变回VISIBLE;mysqldump默认导出该属性,但需确认版本兼容性
怎么验证 INVISIBLE 索引已真正生效
别只信 Query OK 或 SHOW INDEX FROM t\G 的 Visible: NO —— 这些可能有毫秒级延迟或显示偏差。最可靠的是查元数据表 + 执行计划双重验证:
- 查
SELECT INDEX_NAME, IS_VISIBLE FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx_name',返回值必须是字符串'NO' - 执行
EXPLAIN SELECT * FROM t WHERE col = ?,确认key字段为空或改走其他索引;若仍走该索引,大概率是当前会话开启了use_invisible_indexes=on,查SELECT @@optimizer_switch LIKE '%use_invisible_indexes=on%'可确认 -
FORCE INDEX(idx_name)会直接报错ERROR 1176 (HY000): Key 'idx_name' doesn't exist,这不是异常,是设计行为:优化器在解析阶段就注销了不可见索引
压测时必须盯住的三个真实信号,而不是只看 EXPLAIN
单条 EXPLAIN 结果容易误判。真正影响线上性能的是负载下的综合表现,切换后至少观察 24 小时,覆盖完整业务周期:
- 查
performance_schema.table_io_waits_summary_by_index_usage中对应索引的COUNT_STAR是否归零——但注意低频关键查询(如风控拦截、凌晨报表)可能漏统计,不能当唯一依据 - 盯慢查询日志:
SELECT * FROM mysql.slow_log WHERE argument LIKE '%WHERE col = %' AND start_time > DATE_SUB(NOW(), INTERVAL 7 DAY),重点看Query_time突增、Rows_examined暴涨的语句 - 监控
Handler_read_next和Handler_read_rnd_next是否明显上升,这是全表扫描或回表激增的强信号
真正麻烦的不是操作本身,而是应用层残留的硬编码:ORM(如 MyBatis 的 @SelectKey)、中间件 SQL 注释里的 USE INDEX 或 FORCE INDEX,一旦索引设为不可见,这些语句会直接失败。回滚快,但这些地方常被忽略。











