在 Oracle SQL 調優中,WITH 子句(Common Table Expressions, CTE)是簡化複雜查詢、避免重複掃描大表的利器。本文透過實戰案例,示範如何將繁瑣的多層子查詢重構為高效的 CTE 寫法,顯著降低資源消耗。
WITH 子查詢會將中間結果集具體化至臨時段(記憶體或暫存表空間),後續主查詢可多次引用而無需重複存取基表。這對於「先聚合過濾,再多維度交叉分析」的報表型查詢極為有效。
情境:從明細表 ZSXX 抽取 2007/02~06 入庫資料,分別統計稅款(zt='01')、罰款(zt='02')、滯納金(zt='03'),最後按稅種合併呈現。
若直接在主查詢中重複引用 ZSXX 並套用不同 WHERE 條件,資料庫需多次全表掃描與分組,I/O 與 CPU 成本倍增。
WITH rkxx AS (
-- 步驟 1:一次性預處理,過濾日期、聚合至稅種+狀態層級
SELECT sz, zt, SUM(se) AS se
FROM zsxx
WHERE rkrq BETWEEN '2007-02' AND '2007-06'
GROUP BY sz, zt
)
-- 步驟 2:主查詢多次引用輕量級 rkxx,進行條件分組與聯結
SELECT sk.sz,
sk.se AS tax_amt,
fk.se AS penalty_amt,
znj.se AS overdue_amt
FROM (SELECT sz, SUM(se) se FROM rkxx WHERE zt = '01' GROUP BY sz) sk -- 稅款
JOIN (SELECT sz, SUM(se) se FROM rkxx WHERE zt = '02' GROUP BY sz) fk -- 罰款
ON sk.sz = fk.sz
JOIN (SELECT sz, SUM(se) se FROM rkxx WHERE zt = '03' GROUP BY sz) znj -- 滯納金
ON sk.sz = znj.sz;
ZSXX 僅掃描一次,後續運算在小得多的中間結果集上完成。/*+ MATERIALIZE */ 強制具體化。| 場景 | 建議 |
|---|---|
| 多報表共用同一複雜聚合邏輯 | ✅ 強烈推薦 WITH 封裝共用邏輯 |
| 遞迴查詢(組織架構、BOM展開) | ✅ 使用 WITH ... RECURSIVE (11gR2+) |
| 單一查詢、無重複引用 | ⚠️ 評估是否必要,避免過度設計 |
| 中間結果極大(超過暫存表空間) | ❌ 改用全域暫存表 (GTT) 或分步驟 ETL |