Oracle 優化器擁有三種核心表連接算法:Nested Loop Join(嵌套循環)、Sort Merge Join(排序合併)、Hash Join(哈希連接)。理解其底層運作機制、內存模型與適用邊界,是編寫高性能 SQL、解讀執行計劃、實施精準調優的基石。本文深度剖析三大算法原理與實戰選型邏輯。
核心邏輯:將數據集分為 Outer 驅動表(外層循環,執行 1 次)與 Inner 被驅動表(內層循環,執行次數 = Outer 返回行數)。對 Outer 每一行,在 Inner 中查找匹配行。
FOR outer_row IN (SELECT * FROM outer_table) LOOP
FOR inner_row IN (SELECT * FROM inner_table WHERE join_key = outer_row.join_key) LOOP
OUTPUT outer_row + inner_row;
END LOOP;
END LOOP;
關鍵特徵:
核心邏輯:
關鍵特徵:
SORT_AREA_SIZE、SORT_AREA_RETAINED_SIZE(手動 PGA 管理模式)或 PGA_AGGREGATE_TARGET(自動模式)核心邏輯:
關鍵特徵:
HASH_AREA_SIZE 或 PGA_AGGREGATE_TARGET 控制| 維度 | Nested Loop Join | Sort Merge Join | Hash Join |
|---|---|---|---|
| 連接條件類型 | 等值、非等值均可 | 等值、範圍(>、<、>=、<=) | 僅等值 (=) |
| 驅動表大小要求 | Outer 必須小(< 1萬行最佳) | 無嚴格要求,但雙方排序開銷大 | Build Input 必須小(能放入 PGA) |
| 索引依賴度 | 極高(Inner 必須有索引) | 無需索引 | 無需索引 |
| 內存消耗 | 極低(KB 級) | 高(排序區,可能落盤) | 高(哈希表,可能分區溢寫) |
| 並行度支援 | 差(難以並行化) | 好(排序可並行) | 優(Build/Probe 均可並行) |
| 典型應用場景 | OLTP:主鍵/唯一索引查找、小表驅動大表 | 無索引大表關聯、範圍連接、並行查詢 | DW/OLAP:大表等值關聯、星型查詢、事實表關聯維度表 |
| 誤選現象 | 根因 | 修正策略 |
|---|---|---|
| 大表驅動小表走 NLJ | 統計信息缺失/過期,優化器誤判基數 | DBMS_STATS.GATHER_TABLE_STATS、CARDINALITY Hint |
| 小表關聯大表走 HJ 但 PGA 不足溢寫 Temp | PGA_AGGREGATE_TARGET 設置過小 |
調大 PGA、或 Hint USE_NL 強制 NLJ |
| 範圍連接被迫走 NLJ 性能差 | 無索引且優化器不考慮 SMJ | Hint USE_MERGE、創建函數索引 |
| 並行查詢強制走 NLJ | 並行 Hint 與連接方法衝突 | PARALLEL + USE_HASH/USE_MERGE |
-- 強制指定連接方法
SELECT /*+ USE_NL(b) */ * FROM a, b WHERE a.id = b.id; -- Nested Loop
SELECT /*+ USE_HASH(b) */ * FROM a, b WHERE a.id = b.id; -- Hash Join
SELECT /*+ USE_MERGE(b) */ * FROM a, b WHERE a.id = b.id; -- Sort Merge
-- 指定驅動表順序
SELECT /*+ LEADING(a b) USE_HASH(b) */ * FROM a, b WHERE a.id = b.id;
Oracle 12c 引入自適應執行計劃:運行時根據實際行數動態在 NLJ 與 HJ 間切換。
STATISTICS COLLECTOR + NESTED LOOPS/HASH JOIN 並存結構_optimizer_adaptive_threshold 控制(默認 0.5)OPTIMIZER_ADAPTIVE_PLANS=FALSE 關閉小表驅動有索引 → NLJ 穩如泰山
大表關聯無索引、等值連 → HJ 以空間換時間
範圍連接或並行查詢 → SMJ 排序合併不手軟
統計信息要準確,PGA 要給夠,Hint 要慎用,自適應要信任
掌握三大連接算法的本質差異,讓您從「猜測執行計劃」進化為「預判並控制執行計劃」,這正是資深 DBA 與 SQL 調優專家的核心分水嶺。