Hash Join 核心流程
- Build Phase:读取较小行源 (Build Input),在 PGA 中构建哈希表 (分桶) 与位图过滤器。
- Probe Phase:流式读取较大行源 (Probe Input),计算连接键哈希值,探测哈希表,位图快速剔除不匹配行。
- 匹配行直接输出,无需排序,算法复杂度 O(M+N)。
关键参数
| 参数 | 作用 | 建议 |
| HASH_JOIN_ENABLED | 总开关 | TRUE (默认) |
| HASH_AREA_SIZE | 单次 Hash Join 最大内存 (手动管理模式) | ≥ Build Input 预估大小 × 1.2,避免溢写 TEMP |
| PGA_AGGREGATE_TARGET | 自动 PGA 管理总目标 (10g+ 推荐) | 设置合理总值,配合 WORKAREA_SIZE_POLICY=AUTO |
| _HASH_JOIN_BUFFER_SIZE | 隐含参数,控制分区缓冲 | 勿动,除非 Oracle Support 指导 |
内存不足时的分区机制
- Build Input 过大超出
HASH_AREA_SIZE,Oracle 将哈希表分区写入临时表空间 (TEMP)。
- Probe Phase 需多次读取分区文件,I/O 开销指数级上升,性能远低于 NL/SMJ。
- 监控视图:
V$SQL_WORKAREA_ACTIVE 观察 TEMPSEG_SIZE 与 MAX_TEMPSEG_SIZE。
执行计划识别与 Hint
-- 强制 Hash Join
SELECT /*+ USE_HASH(EMP) */ * FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;
-- 禁用 Hash Join (强制 NL)
SELECT /*+ USE_NL(EMP) */ * FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;
-- 指定 Build 表 (较小表)
SELECT /*+ LEADING(DEPT) USE_HASH(EMP) */ * FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;
适用性速查
| 条件 | 结论 |
| 等值连接 + 大表 + 内存充足 | ✅ 首选 Hash Join |
| 非等值连接 | ❌ 不支持 (仅 SMJ/NL) |
| Build 表极小 (≤ 几百行) | ✅ NL 可能更快 (无 Build 开销) |
| PGA 压力大、并发高 | ⚠️ 评估溢写风险,考虑 NL |
| 并行查询 (PX) | ✅ Hash Join 并行化成熟 (PQ Distrib: HASH/HASH) |
最佳实践清单
- 收集列级直方图 (
METHOD_OPT=>'FOR ALL COLUMNS SIZE SKEWONLY'),提升基数估算准确度。
- 监控
V$SYSSTAT 中 hash join 与 hash join failed 计数器。
- 大表连接前预估 Build Input 大小:
SELECT SUM(BYTES) FROM USER_SEGMENTS WHERE SEGMENT_NAME IN (SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME='...') 粗略参考。
- 必要时用
OPT_ESTIMATE Hint 修正优化器基数误判。