应根据数据量、索引和连接条件选择:驱动表小且内表连接列有高效索引时选use_nl;两大数据表等值连接且内存充足时选use_hash;非等值连接(如between)且需排序时选use_merge,但须确保排序前提或接受隐式开销。

USE_NL / USE_HASH / USE_MERGE 怎么选,看数据量和索引情况
选错 JOIN 算法是 Hint 用崩的最常见原因。优化器默认选的不一定错,但业务侧如果清楚驱动表小、连接列有高效索引,就该用 USE_NL;如果两个大表等值 JOIN 且内存够,USE_HASH 更稳;非等值条件(比如 WHERE a.date BETWEEN b.start AND b.end)基本只能靠 USE_MERGE,前提是两边都已按连接键排序。
注意:USE_NL 后必须跟「内表名」,不是随便写个表——它表示“用前面的表去驱动这个表”;USE_HASH 和 USE_MERGE 则要求括号里是参与该次 JOIN 的两个表,顺序不敏感。
-
USE_NL(t2)表示 t1 驱动 t2(t1 必须在LEADING中作为前导) -
USE_HASH(t2, t3)表示对 t2 和 t3 这一对做哈希连接 -
USE_MERGE(t3, t4)要求 t3 和 t4 在执行前已按连接列排好序,否则会先触发隐式排序,反而拖慢
LEADING 是 JOIN 顺序的锚点,不配它,USE_NL 很可能失效
LEADING 不是可选项,是前提。没有它,USE_NL(t2) 只能告诉优化器“如果 t2 是内表,就用 NL”,但优化器仍可能把 t2 当外表——结果就是 Hint 被忽略,执行计划照旧走 HASH 或 MERGE。
正确写法必须明确内外关系:/*+ LEADING(t1 t2) USE_NL(t2) */ 表示 t1 是外表、t2 是内表,且 t1 先被访问;若想让 t2 驱动 t3,则要写成 /*+ LEADING(t1 (t2 t3)) USE_NL(t3) */,括号表示 t2 和 t3 构成一个内层组合。
- 表名必须用别名,且别名需在 FROM 中定义过
- 不能出现循环依赖,比如
LEADING((t1 t2) (t2 t3))会让优化器报错 - Oracle 中
ORDERED是LEADING的简化替代,但它不指定内外表,只保 FROM 顺序,灵活性差很多
强制算法后还要防“假成功”:检查执行计划里的实际操作符
加了 Hint 不等于生效。MySQL 8.0.20+、Oracle、SQL Server 都支持 EXPLAIN 或 EXPLAIN PLAN,但关键要看输出里是不是真出现了 NESTED LOOP、HASH JOIN 或 MERGE JOIN 字样,而不是只看到 “Join Filter” 或 “Hash Cond”。
特别容易被忽略的是:某些数据库(如旧版 MySQL)不识别标准 Hint 语法,你写了 /*+ USE_HASH(t1,t2) */,它直接当普通注释跳过,执行计划里还是 JOIN —— 此时得查文档确认当前版本是否支持该 Hint,或改用语句级语法(如 MySQL 的 SELECT ... STRAIGHT_JOIN ...)。
- PostgreSQL 不支持这类 Hint,得靠
SET enable_hashjoin = off等 GUC 参数临时干预 - SQL Server 中
LOOP JOIN是查询级提示,写法是SELECT * FROM t1 INNER LOOP JOIN t2 ON ...,不是注释形式 - Oracle 执行计划中若出现
VIEW或UNION-ALL节点,Hint 可能只作用于子节点,主查询仍走默认路径
为什么 USE_NL(t2) 有时比 USE_HASH(t1,t2) 还慢?因为没控住驱动表大小
嵌套循环快的前提是:外表结果集极小(比如 WHERE id = ? 返回 1 行),且内表连接列有索引。一旦外表因过滤条件弱返回几千行,而内表又没走索引(比如用了函数索引但 WHERE 里写了 UPPER(name)),USE_NL 就会退化成 N×M 全扫描,比哈希连接慢一个数量级。
这时候光加 USE_NL 没用,得配套加索引 Hint:/*+ LEADING(t1) INDEX(t1 pk_id) USE_NL(t2) INDEX(t2 idx_fk) */。否则优化器可能在外表扫描时用了全表扫描,再用 NL 去反复查内表,等于把性能问题放大了。
- 不要单独用
USE_NL,它只是“连接方式”,不是“性能保证” - 每加一个 Hint,都要反问:我有没有同时控制住驱动表的数据量?内表有没有可用索引?
- 线上环境第一次加 Hint,务必对比
EXPLAIN FORMAT=JSON里的rows_examined和filtered字段,确认预估行数是否合理










