index merge intersection 仅在where中所有子条件均为独立单列索引且严格等值匹配时才可能启用,例如user_id = 123 and status = 'paid';若含范围查询、like、隐式转换、联合索引未完整命中或高基数匹配,优化器将放弃该策略。

Index Merge Intersection 什么条件下会真正启用
只有当 WHERE 中所有子条件都满足「独立单列索引 + 完整等值匹配」时,index_merge_intersection 才可能被选中。它不是“有 AND 就上”,而是极其挑剔:比如表上有 INDEX(user_id) 和 INDEX(status),但查询写成 WHERE user_id = 123 AND status IN ('paid', 'pending'),status 部分是 range 扫描,就无法触发 intersect;同理,WHERE user_id = 123 AND status LIKE 'p%' 也不行。
常见误判点:
- 联合索引存在但未被完整命中(如
INDEX(user_id, status),只用user_id = 123)→ 不参与 intersection - 字段存在隐式类型转换(如
status = 1但字段是VARCHAR)→ 索引失效,自然不合并 - 任一条件返回主键数过大(比如
status = 'active'匹配全表 70% 行)→ 优化器直接放弃,改走全表或联合索引
如何确认 MySQL 正在用 Index Merge
靠 EXPLAIN 看三项关键输出:
-
type列必须是index_merge -
key列显示多个索引名,例如user_id,status -
Extra出现Using intersect(user_id,status)或Using union(user_id,status)
注意:Using sort_union 表示至少一个索引扫描结果未按主键有序(非 ROR),MySQL 被迫先排序再合并——这通常意味着性能更差,且无法利用 LIMIT 提前终止。
关闭 Index Merge 的实际操作方式
MySQL 没有全局开关直接禁用 Index Merge,但可通过以下两种方式有效绕过:
- 设置会话级优化器标志:
SET optimizer_switch='index_merge=off,index_merge_union=off,index_merge_sort_union=off,index_merge_intersection=off'; - 在 SQL 中加优化器提示:
SELECT /*+ NO_INDEX_MERGE(t) */ * FROM t WHERE a = 1 AND b = 2;(MySQL 8.0.20+ 支持)
不建议在全局配置中硬关,因为某些无合适联合索引的旧表可能依赖它避免全表扫描;更稳妥的做法是针对性地在慢查询里加提示,再配合补建联合索引。
为什么补联合索引比调优器开关更可靠
Index Merge 是优化器在“没得选”时的兜底策略,本质是多次索引树遍历 + 内存/磁盘集合运算 + 回表,I/O 和 CPU 开销远高于一次联合索引 B+ 树定位。实测中,INDEX(a,b) 查询 WHERE a = ? AND b = ? 比 INDEX(a)+INDEX(b) 触发 intersect 快 5 倍以上,且 LIMIT 10 能立刻生效,而后者常需合并全部结果才截断。
真正容易被忽略的是:即使你写了 WHERE a = ? AND b = ?,只要 b 字段有 NULL 值且索引未设 NOT NULL,InnoDB 可能拒绝使用该字段参与 intersect —— 这类细节在 EXPLAIN 里完全不报错,只能靠观察 key_len 和实际执行时间交叉验证。











