using merge 表示mysql优化器选择索引合并策略,即同时使用多个单列索引并在内存中归并结果,通常因缺失合适复合索引或含or条件导致,易引发死锁和性能下降。

Using merge 不是索引类型,而是 MySQL 执行计划中一个明确的警告信号:优化器决定同时使用多个单列索引,并在内存中做交集/并集运算——这通常意味着没走好复合索引,且容易引发死锁和性能抖动。
EXPLAIN 中看到 Using merge 说明什么
它出现在 Extra 列里,比如:Extra: Using merge 或更完整的 Using sort_union(idx_a,idx_b); Using intersect(uk_accept_id,idx_status)。这表示 MySQL 放弃了单个高效索引,转而用 index merge 策略组合多个索引结果。
- 常见诱因是 WHERE 条件含多个 OR(如
WHERE a = 1 OR b = 2)或 AND 连接的非前缀列(如WHERE status = 'done' AND accept_id = 123,但没建(status, accept_id)复合索引) - MySQL 5.6+ 默认开启
index_merge优化,但它的成本估算常不准,尤其在高并发更新场景下 - 它不等价于“用了多个索引”——真正执行时仍是逐个索引扫描 + 内存归并,I/O 和 CPU 开销反而更高
Using merge 为什么容易导致死锁
当两个事务分别以不同顺序访问同一组索引(例如事务 A 先读 uk_accept_id 再锁 idx_status,事务 B 反过来),就可能形成循环等待。index merge 的执行路径不可控,加剧了这种不确定性。
- 典型案例如:UPDATE 语句命中
uk_accept_id和idx_status两个索引,两事务并发执行时触发死锁 - 死锁日志里常出现类似
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: ... index uk_accept_id ... *** (2) HOLDS THE LOCK(S): ... index idx_status ... - MyISAM 表不会死锁,但 InnoDB 下 index merge 是死锁高发区之一
怎么关掉或绕过 Using merge
不推荐全局关闭 optimizer_switch='index_merge=off',更稳妥的是针对性干预:
- 建合适的复合索引替代,例如把
WHERE status = ? AND accept_id = ?的查询,对应建INDEX idx_status_accept (status, accept_id) - 用
FORCE INDEX指定唯一主索引或覆盖索引,如SELECT * FROM t FORCE INDEX (PRIMARY) WHERE ... - 改写 OR 条件为 UNION ALL(需确保子查询无重叠),让优化器放弃 merge 尝试
- 检查
row_count和filtered列:如果rows很大但filtered极低,说明 index merge 实际效果差,应优先优化条件选择性
merge 引擎表和 Using merge 完全无关
别被名字误导:MERGE 存储引擎(MRG_MyISAM)是分表聚合方案,和执行计划里的 Using merge 没半点关系。前者是表组织方式,后者是索引访问策略。混淆这两者会导致排查方向完全错误。
真正要盯住的,永远是 EXPLAIN 输出里的 type、key、Extra 三列——尤其是 Extra 出现任何 Using 开头的提示,都值得停下来看两眼。











