索引合并(index_merge)是联合索引缺失时的权宜之计,常导致性能下降;应优先设计匹配WHERE条件的联合索引,避免依赖多次二级索引扫描与归并。

索引合并(index_merge)不是优化组合查询的推荐路径,而是联合索引缺失时的权宜之计;它常让查询变慢而非变快,尤其在电商、订单、商品等高频范围过滤场景下。
看到 type=index_merge 就该警觉
这不代表“用了多个索引=性能好”,恰恰相反:MySQL 正在被迫做多次二级索引扫描 + 主键归并 + 回表,I/O 和 CPU 开销远高于单次高效联合索引扫描。
- EXPLAIN 中
key显示多个索引名(如idx_price,idx_category_id),key_len很小,rows高,Extra出现Using union()或Using sort_union()→ 典型低效信号 - WHERE 中含
OR(如status = 'on_sale' OR is_new_arrival = 1)或深度嵌套的AND/OR(如(a=1 OR b=2) AND c > '2024'),又没对应联合索引 → 极易触发index_merge - 本地小表测试可能不走
index_merge,但生产大表(百万级以上)一查就慢,因为优化器在数据量小时低估归并成本
优先建对联合索引,而不是依赖 index_merge
90% 触发 index_merge 的查询,本质是联合索引设计没跟上 WHERE 模式。比如:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
WHERE category_id = 123 AND price BETWEEN 99 AND 299→ 应建INDEX(category_id, price),而非分别建idx_category_id和idx_price -
WHERE user_id = 1001 AND created_at > '2026-01-01' ORDER BY updated_at DESC→ 建INDEX(user_id, created_at, updated_at),覆盖过滤+排序 - 字段顺序不能错:
INDEX(a,b)对WHERE b = ?完全无效;若b单独查询多,再补INDEX(b),但要评估写入压力
真要临时用 index_merge,得控制它的触发条件
仅当确认无法改 SQL、无法加联合索引,且 OR 条件选择性极高(如 id IN (1,2,3))时,才考虑让它工作——但必须验证是否真比全表扫描快。
- 用
FORCE INDEX强制走某个联合索引,比放任优化器选index_merge更可控:SELECT * FROM orders FORCE INDEX(idx_user_status) WHERE user_id = 1001 AND status IN ('paid','shipped') - 会话级禁用(慎用):
SET SESSION optimizer_switch='index_merge=off';,避免优化器“有得选”却选错 - 删掉冗余单列索引:
DROP INDEX idx_price ON products;,减少优化器误判机会;保留主键 + 必要联合索引 + 极少数高频单列过滤索引即可
真正难的不是让 index_merge 跑起来,而是判断它是不是当前查询最差的执行路径——而这个判断,必须基于 EXPLAIN 的 rows、key_len、Extra 和真实执行时间,不是看 type 是否等于 index_merge。

















