在MySQL的查询优化过程中,当WHERE子句包含多个针对单列索引的条件且彼此以OR或AND连接时,优化器可能会选择索引合并(index merge)访问方式。其中MERGE是这类算法的统称,而UNION、MERGE_UNION与SORT_UNION则是具体的合并策略。它们最核心的区别在于如何扫描多个索引以及如何处理拿到的行指针(ROWID)。

一、什么是索引合并中的MERGE
MERGE并不是某一种独立算法,而是MySQL对“同时利用多个索引然后合并结果”这一类访问路径的统称。在EXPLAIN输出的Extra列中,你可能会看到Using index merge,这说明优化器没有选择全表扫描,也没有强行只用其中一个索引,而是分头扫描多个索引,再把中间结果按规则合并。
这种机制的出现,是因为早期MySQL版本不允许在单个查询里同时使用两个独立索引。后来引入了index merge,才使得形如WHERE a=1 OR b=2这样的条件可以分别走idx_a和idx_b,再合并主键。MERGE之下具体分为交集(intersect)、并集(union)和排序后并集(sort_union)等类型,日常讨论里的MERGE_UNION往往就是指并集合并这一类。
二、UNION与MERGE_UNION的执行逻辑
当查询条件是多个等值匹配的OR关系,例如WHERE col1=10 OR col2=20,并且col1、col2上各有独立索引,优化器可能采用UNION合并。它分别通过两个索引拿到符合条件的ROWID集合,由于每个索引在等值查找时返回的主键本身就是有序的,因此可以直接做归并取并集,不需要额外排序。
在MySQL源码与官方文档语境中,这种“对多个索引扫描结果取并集”的策略常被称为union merge,也就是很多资料写的MERGE_UNION。下面是一个简单的表结构和触发示例:
CREATE TABLE user ( id INT PRIMARY KEY, age INT, city VARCHAR(50), INDEX idx_age (age), INDEX idx_city (city) ); EXPLAIN SELECT * FROM user WHERE age = 25 OR city = 'beijing';
如果Extra显示Using union(idx_age,idx_city),就说明走了UNION合并。它的优点是避免了全表扫描,且因为等值查询返回的ROWID有序,合并代价较低;缺点是仍要维护多个索引扫描游标,并在Server层做去重。
三、SORT_UNION适用的场景与代价
当OR连接的条件里包含范围查询,例如WHERE age > 20 OR city < 'z',单个索引返回的行指针顺序未必能直接归并,优化器就会选择SORT_UNION。它会先分别从各索引取出ROWID,放入内存或临时文件排序,再有序合并去重。
相比UNION,SORT_UNION多了一道排序操作,因此在EXPLAIN中你会看到Using sort_union(idx_age,idx_city)。下面的代码展示了范围OR条件可能触发该策略:
EXPLAIN SELECT * FROM user WHERE age > 30 OR city < 'shanghai';
由于排序可能涉及磁盘临时表,SORT_UNION通常比UNION更重。如果业务频繁出现这类查询,更合理的做法是评估能否建立联合索引,或者改写SQL,让优化器走更高效的访问路径。
四、三者在执行计划与性能上的对比
我们可以用一张表来归纳它们的差异:
| 合并类型 | 典型条件 | 是否需要排序 | EXPLAIN标识 |
|---|---|---|---|
| UNION / MERGE_UNION | 多个等值OR | 否 | Using union(...) |
| SORT_UNION | 含范围查询的OR | 是 | Using sort_union(...) |
| MERGE(统称) | 上述各类合并的总称 | 视子类而定 | Using index merge |
从性能角度讲,UNION因为免排序通常最快,SORT_UNION在大数据量下可能因排序产生明显开销。MERGE作为总称,本身不决定效率,真正要看的是它下属的具体合并方式。索引合并虽好,但往往意味着缺少更合适的联合索引,长期应通过表结构优化来减少对其依赖。
五、如何判断是否该干预索引合并
如果你在慢查询日志中发现大量Using sort_union,且扫描行数很高,可以先用optimizer_switch观察关闭索引合并后的计划,再决定是保留还是改索引。例如建立(age, city)的联合索引,可能让查询直接走ref或range,彻底避开合并。
需要注意的是,索引合并受index_merge、index_merge_union、index_merge_sort_union等开关控制。生产环境调整前应在测试库验证,避免误关union导致原本高效的查询退化为全表扫描。
-- 查看当前优化器开关 SHOW VARIABLES LIKE 'optimizer_switch'; -- 临时关闭sort_union观察影响 SET optimizer_switch = 'index_merge_sort_union=off'; EXPLAIN SELECT * FROM user WHERE age > 30 OR city < 'shanghai';
理清MERGE、UNION与SORT_UNION的差异,不只是为了读懂执行计划,更能指导我们判断索引设计是否合理,从而在根本上减少不必要的合并与排序开销。
MySQLindex_mergeunion_merge修改时间:2026-08-07 01:00:27