隐藏索引不是性能优化手段,而是安全验证索引删除影响的工具;必须用alter table ... alter index ... invisible创建或切换,gui工具不支持;默认不被explain使用,需检查optimizer_switch并结合慢日志、performance_schema及handler指标综合判断是否生效。

隐藏索引不是用来“优化查询”的,而是让你安全验证“去掉某个索引后查询会不会变慢”——它本身不提速,只帮你避坑。
怎么创建或切换已有索引为隐藏
必须用 ALTER TABLE ... ALTER INDEX ... INVISIBLE,GUI 工具(Workbench、DBeaver 等)点不动,写了也白写。
-
ALTER TABLE orders ALTER INDEX idx_user_id INVISIBLE;—— 切换已有索引,毫秒完成,不锁表 -
CREATE INDEX idx_status ON orders(status) INVISIBLE;—— 新建即隐藏,推荐用于压测前预埋 - 主键、第一个
UNIQUE NOT NULL索引、FULLTEXT或SPATIAL索引会直接报错ERROR 3522 (HY000),别试 - 执行后立刻查
INFORMATION_SCHEMA.STATISTICS:确认IS_VISIBLE = 'NO'(注意是字符串,不是布尔值)
为什么 EXPLAIN 还是走了那个索引?
默认情况下,EXPLAIN 根本不认隐藏索引——哪怕你写 FORCE INDEX(idx_user_id),也会静默忽略,退回到全表扫描或别的索引。这不是 bug,是设计行为。
- 先查开关:
SELECT @@optimizer_switch LIKE '%use_invisible_indexes=on%';,如果返回 1,说明有人开了全局或会话级开关,导致隐藏失效 - 压测前务必关掉:
SET SESSION optimizer_switch = 'use_invisible_indexes=off'; - 想临时对比?用提示:
SELECT /*+ SET_VAR(optimizer_switch = "use_invisible_indexes=on") */ * FROM orders WHERE user_id = 123;(仅 MySQL 8.0.22+ 支持)
压测时怎么判断隐藏真生效了
不能只看一条 EXPLAIN 的 key 字段为空——得看三类信号是否同步出现:
- 慢查询日志里,原本走该索引的语句
Query_time明显升高,或Rows_examined暴涨 -
performance_schema.table_io_waits_summary_by_index_usage中对应索引的COUNT_STAR归零(但采样不准,仅作参考) -
Handler_read_next或Handler_read_rnd_next指标陡增——说明优化器被迫回表或全表扫描 - 最关键一点:写入压力不变,但
QPS下降、CPU升高、磁盘IO暴涨?那很可能是隐藏索引还在后台默默维护 B+ 树——它不省写入开销
最容易被忽略的点:隐藏索引照常消耗写入资源。哪怕设为 INVISIBLE,INSERT/UPDATE/DELETE 仍实时更新 B+ 树、校验唯一性。压测中若发现写入性能劣化,别只盯着查询计划看。











