真正生效的是/+ USE_HASH(a) /,需配合半连接结构、驱动表小、被驱动表有统计信息;USE_HASH_AGGREGATION仅适用于聚合操作,对半连接无效。

直接结论:用 /*+ USE_HASH_AGGREGATION */ 不起作用,真正生效的是 /*+ USE_HASH(a) */ 配合相关子查询结构,且必须确保驱动表(外层)小、被驱动表(内层)有统计信息。
为什么 USE_HASH_AGGREGATION 对半连接无效
这个提示是给聚合操作(如 GROUP BY)用的,不是为半连接设计的。Oracle 优化器看到 EXISTS 或 IN 子查询时,内部会将其归约为半连接(semi-join),但不会触发哈希聚合逻辑。强行加这个 hint,优化器会忽略,执行计划里依然显示 HASH JOIN RIGHT SEMI 是它自己选的,不是你“强制”的。
- 查
V$SQL_HINT可确认:USE_HASH_AGGREGATION的CLASS是AGGREGATION,和SEMIJOIN无关 - 实际测试中加了该 hint 后,
EXPLAIN PLAN输出的Operation列不变,Hint Report里会写unused
USE_HASH(a) 才是半连接场景下真正可控的 hint
这里的 a 必须是子查询中被驱动的表别名(即内层表),且该表要参与哈希构建。Oracle 半连接默认把子查询表当作“右表”,所以 USE_HASH(a) 实际上是在告诉优化器:“对子查询中的表 a 做哈希构建,外层表逐行探测”。
- 写法示例:
SELECT a.owner, a.object_id FROM v_t1t2 a WHERE EXISTS ( SELECT /*+ USE_HASH(b) */ 1 FROM t99 b WHERE a.object_id = b.object_id );
- 关键前提:
t99表要有准确统计信息(DBMS_STATS.GATHER_TABLE_STATS),否则优化器可能因误估行数而弃用哈希 - 如果子查询用了
UNION ALL视图(如v_t1t2),hint 必须放在子查询内部,不能放在外层
容易被忽略的三个硬性条件
即使 hint 写对,Oracle 也可能不走哈希半连接——这不是 bug,是优化器在成本模型下的合理规避。
-
t99表实际返回行数 > 10000 时,优化器倾向改用排序归并(SORT MERGE JOIN RIGHT SEMI),因为哈希内存压力大;此时需配合/*+ OPT_PARAM('_hash_join_enabled' 'true') */确保开关开着(默认开启,但某些补丁版本可能关闭) - 外层表
v_t1t2如果没统计信息,优化器无法判断它是否“小”,就可能放弃 nested loops + hash semi 的组合路径 - 连接列(
object_id)若在t99上无索引,USE_HASH(b)仍有效;但若有索引且选择性极高(NESTED LOOPS SEMI —— 这是正确行为,不是 hint 失效
真正难控制的点不在 hint 语法,而在统计信息质量与数据分布偏差。比如 t99 表只有 99 行,但优化器统计显示 5000 行,它就会拒绝哈希路径。这种时候,与其死磕 hint,不如先跑一遍 DBMS_STATS.GATHER_TABLE_STATS 并确认 NUM_ROWS 准确。


















