OPTION (MERGE JOIN) 仅为建议而非强制指令,仅当连接列类型严格一致、均有匹配方向的有序索引、且输入为Ordered=true的索引扫描/查找时才生效;否则静默忽略,可能退为Hash Join。

OPTION (MERGE JOIN) 不是强制指令,只是建议
SQL Server 的 OPTION (MERGE JOIN) 提示不会强制执行 Merge Join,它只在满足全部硬性前提时才被优化器采纳;任一条件不满足,提示就被静默忽略,执行计划里甚至不会出现 Merge Join 算子。
常见失效场景包括:
-
ON条件不是纯等值比较(如用了、>、BETWEEN) - 连接列存在隐式类型转换(如
int对varchar)或显式函数包装(如UPPER(a.col)、ISNULL(a.col, '')) - 任一表的连接列上没有物理有序索引(即索引键顺序严格匹配
ON字段,且方向一致) - 统计信息严重过期(
ActualRows / EstimatedRows > 5或modification_counter > 总行数 × 20%)
真正让 OPTION (MERGE JOIN) 生效的三个必要条件
必须同时满足,缺一不可:
- 两表连接列数据类型完全一致(
int对int,datetime2(3)对datetime2(3)),且无任何表达式包装 - 两表均在连接列上有单列索引(或复合索引中该列为最左前缀),且索引定义方向相同(都是
ASC或都是DESC)——例如:CREATE INDEX ix_t1_a ON t1(a ASC)和CREATE INDEX ix_t2_a ON t2(a ASC) - 执行计划中两个输入节点必须是
Index Scan或Clustered Index Seek,且属性Ordered="true"(需通过SET STATISTICS XML ON查看实际执行计划 XML)
为什么加了提示还是看到 Hash Join?
这不是 bug,而是优化器理性放弃。当以下任一情况成立时,Hash Join 实际更优,优化器会直接无视提示:
- 其中一张表很小(比如 Nested Loops 的
O(M log N)成本低于 Merge 的O(M + N) - 两表都无序,建索引成本远高于一次哈希构建(尤其写多读少场景)
- 内存充足且 Hash Join 的
Memory Grant能满足,而 Merge Join 需要稳定流式输出但上游有TOP、OFFSET或FOR XML导致排序流中断
此时强行加 OPTION (MERGE JOIN) 不仅无效,还可能掩盖真实瓶颈——比如你该优化的是统计信息或索引设计,而不是执拗于算子形状。
验证是否真走免排序 Merge Join 的唯一方式
别信图形执行计划里那个“Merge Join”图标。打开实际执行计划(SET STATISTICS XML ON),定位到 <relop logicalop="Merge Join"></relop> 节点,再往下查它的两个直接子节点:
- 必须都是
Index Scan或Clustered Index Seek(不能是Table Scan、Non-Clustered Index Scan除非索引键顺序 100% 匹配) - 两个子节点的
Ordered属性必须同时为true - 两个子节点的
EstimatedRows和ActualRows偏差不能超过 5 倍;否则运行DBCC SHOW_STATISTICS('table', 'index')检查modification_counter,超 20% 就立刻UPDATE STATISTICS table WITH FULLSCAN
只要任一子节点带 Sort 操作符(哪怕藏在下方第三层),就说明 Merge Join 在“假装有序”,CPU 高就是它干的——这时候删掉 OPTION (MERGE JOIN) 反而更诚实。

















