MySQL OR 条件什么时候会选择 Index Merge
来源:17golang原创
时间:2026-09-10 14:09:44 373浏览 收藏
MySQL 的 OR 条件并不是“有两个索引就一定分别查一遍”。当同一张表的多个条件能够转换成独立的范围扫描,而且合并这些扫描的成本低于其他访问路径时,优化器才可能选择 Index Merge。最可靠的判断方法是看 EXPLAIN:type 出现 index_merge,key 列列出多个索引,Extra 再显示 Using union(...) 或 Using sort_union(...)。
官方地址:https://dev.mysql.com/doc/refman/8.4/en/index-merge-optimization.html
- 等值 OR 常见于 Index Merge union,范围 OR 可能落到 sort_union。
- 出现
index_merge只说明优化器选了这种计划,不代表它一定比复合索引快。 - 先看
rows、回表列和Extra,再用改写或单语句开关做对照。
先用 EXPLAIN 判断是否真的走 Index Merge
先准备一条边界清楚的查询。假设 orders 上分别有 customer_id 和 status 索引,查询只关心两个入口之一命中的订单:
-- 用 EXPLAIN 观察 OR 条件实际选择了哪些访问路径
EXPLAIN SELECT order_id, customer_id, status, created_at
FROM orders
WHERE customer_id = 1088 OR status = '待支付';
重点记录四列,而不是只盯着一行“命中索引”的结论:
| 字段 | 怎么看 |
|---|---|
type | index_merge 表示多个索引范围结果被合并。 |
key | 查看实际参与的索引名称,通常不止一个。 |
rows | 估算需要检查的行数;多个分支都很宽时,合并未必划算。 |
Extra | 区分 Using union、Using sort_union 以及后续回表。 |
OR 条件为什么可能选择 Index Merge
Index Merge 只针对同一张表的多个 range 扫描。对于上面的两个等值分支,MySQL 可以分别从两个 B-Tree 索引拿到行标识,再做并集和去重;这通常对应 Using union(customer_id_idx,status_idx)。它不是跨表把两个查询拼起来,也不是把两个索引物理合成一个新索引。

如果 OR 两边是较宽的范围,例如 created_at ...,普通 union 不一定适用,优化器可能先收集全部行标识、排序后再合并,Extra 会出现 Using sort_union(...)。而多个条件用 AND 组合时,才可能看到 intersect;不要把 intersect 的规则套到 OR 查询上。
发现计划不合适时怎么调整
Index Merge 的选择来自成本估算。两个单列索引虽然都能过滤,但最终 SELECT 还要取很多非索引列,就会产生大量回表;若两个条件的选择性都不高,先各自扫描再合并可能还不如一次顺序访问。可以用一条只取索引列的对照查询,确认回表是否是主要代价:
-- 只取两个索引列,帮助区分“合并索引”与“回表取整行”的影响
EXPLAIN SELECT customer_id, status
FROM orders
WHERE customer_id = 1088 OR status = '待支付';
如果业务查询总是围绕同一组条件,优先评估更贴合访问模式的复合索引;如果 OR 结构很深,可先按等价逻辑重新加括号,让每个分支更容易转换成范围条件。改动后必须重新看 key、rows 和实际耗时,不能只凭执行计划名称下结论。
用单语句对照实验确认取舍
需要判断 Index Merge 是否真的有益时,先在测试会话或低风险环境做对照。MySQL 通过 optimizer_switch 控制相关算法,也支持按语句影响优化器;一次只改变一个因素,避免把统计信息、索引和开关同时改掉。
-- 仅在当前会话关闭 Index Merge,和默认计划做同一条 SQL 的对照
SET SESSION optimizer_switch = 'index_merge=off';
EXPLAIN SELECT order_id, customer_id, status, created_at
FROM orders
WHERE customer_id = 1088 OR status = '待支付';
-- 对照完成后恢复默认开关,避免影响后续查询
SET SESSION optimizer_switch = 'index_merge=on';
对比时至少保留两份 EXPLAIN:默认计划和关闭合并后的计划。若关闭后变成单索引扫描但 rows 更大,不代表默认合并就绝对正确,还要结合返回行数、缓存命中、排序和线上延迟观察。生产环境更适合通过影子流量或灰度查询验证,再决定是否调整索引。

相关问题
Index Merge 和复合索引哪个更快?
没有固定答案。条件稳定且组合规律明确时,复合索引可能减少合并与回表;条件变化大时,Index Merge 可能更灵活,最终以同数据分布下的计划和实测为准。
为什么写了 OR 却看不到 index_merge?
OR 两侧可能无法形成合适的 range,或者优化器估算其他路径成本更低。先检查括号、列上是否有可用索引,再看 rows 和统计信息。
能不能强制每个 OR 分支都使用索引?
不建议先强制。索引提示或优化器开关只适合有对照证据的场景,数据分布变化后原计划可能反而变慢。
判断 MySQL OR 条件是否会选择 Index Merge,核心不是背一个固定语法,而是把“条件形状—索引分支—合并方式—回表成本”连起来,再用 EXPLAIN 和可回滚的对照实验确认。
-
499 收藏
-
206 收藏
-
500 收藏
-
193 收藏
-
270 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习