| 場景 | WHERE | HAVING | 建議 |
| 過濾條件不涉及彙總欄位 | 可用 Rushmore 技術 (索引) | 無法用索引,需先彙總再過濾 | 優先用 WHERE |
| 過濾條件涉及彙總欄位 (SUM, COUNT 等) | 彙總前執行,欄位值未定 → 錯誤/無效 | 彙總後執行,正確語意 | 必須用 HAVING |
避免使用 HAVING 的效能代價
- HAVING 需要:排序 → 分組 → 彙總 → 過濾
- WHERE 可在彙總前過濾,大幅減少參與彙總的資料量
- 能用 WHERE 解決的,堅決不用 HAVING
子查詢減少表存取
-- 低效:多次存取 TAB_COLUMNS
SELECT tab_name FROM tables
WHERE (tab_name, db_ver) = (SELECT tab_name, db_ver FROM tab_columns WHERE version = 604);
-- 高效:單次存取配合 EXISTS
SELECT tab_name FROM tables t
WHERE EXISTS (SELECT 1 FROM tab_columns c
WHERE c.tab_name = t.tab_name
AND c.db_ver = t.db_ver
AND c.version = 604);
內部函數提升 SQL 效率
- 善用
DECODE、CASE、NVL、COALESCE 處理條件邏輯
- 單次掃描完成複雜轉換,避免多次自聯結或子查詢
- 12c+ 可用
APPROX_COUNT_DISTINCT 近似聚合加速
表別名最佳實踐
- 多表聯結必須使用別名
- 所有欄位引用加上別名前綴:
e.empno、d.deptno
- 減少解析時間、消除欄位歧義錯誤
EXISTS vs IN / NOT EXISTS vs NOT IN
| 對比 | IN / NOT IN | EXISTS / NOT EXISTS |
| 子查詢執行 | 通常先執行子查詢產生結果集 | 相關子查詢,逐列驅動檢查 |
| NULL 處理 | NOT IN 含 NULL 回傳空結果 (陷阱) | 正確處理 NULL 語意 |
| 效能 | 大結果集時需排序合併 | 滿足條件立即返回,適合大表驅動小表 |
| 全表掃描 | NOT IN 子查詢表常全表掃描 | 可利用索引快速判斷 |
改寫範例
-- 低效 NOT IN
SELECT * FROM emp WHERE deptno NOT IN (SELECT deptno FROM dept WHERE loc = 'MELB');
-- 高效 NOT EXISTS
SELECT * FROM emp e WHERE NOT EXISTS (
SELECT 1 FROM dept d WHERE d.deptno = e.deptno AND d.loc = 'MELB'
);
-- 外部聯結替代 (舊版寫法)
SELECT e.* FROM emp e, dept d
WHERE e.deptno = d.deptno(+) AND d.loc IS NULL;
- 上一篇文章: Oracle FROM/WHERE 子句效能優化實戰:表順序、條件排列、ARRAYSIZE 與 TRUNCATE 技巧
- 下一篇文章: Oracle EXISTS 用法精要:替代 DISTINCT、索引維護與 SQL 撰寫規範
Copyright ©
程式碼之家 All Rights Reserved