SQL 語句寫得對不代表寫得好。掌握以下 11 項優化技巧,能顯著提升 Oracle 查詢效能,減少資源消耗。
Oracle 解析 WHERE 子句採用自下而上順序。因此:
`*` 會觸發資料字典查詢以展開所有欄位名稱,增加解析開銷。明確列出所需欄位。
使用 `DECODE` 或 `CASE` 可在單次掃描中完成多條件邏輯,避免多次掃描同一表或重複連接。
| 特性 | DELETE | TRUNCATE |
|---|---|---|
| 類型 | DML | DDL |
| 回滾段 | 記錄可恢復資訊 | 不記錄,不可恢復 |
| 觸發器 | 觸發 | 不觸發 |
| 速度 | 慢 | 極快 |
| 適用 | 條件刪除 | 全表清空 |
每次 `COMMIT` 釋放:
長交易拆分為小批次提交可降低鎖爭用與 Undo 保留壓力。
多表連接時,為每個表指定簡短別名,並在所有欄位引用前加上別名(如 `e.empno`),可減少解析時間並避免欄位歧義錯誤。
低效:
SELECT * FROM emp WHERE deptno IN (SELECT deptno FROM dept WHERE loc = 'MELB')
高效:
SELECT * FROM emp e WHERE EXISTS (SELECT 'X' FROM dept d WHERE d.deptno = e.deptno AND d.loc = 'MELB')
原因:`NOT IN` 會對子查詢執行全表掃描並內部排序合併;`EXISTS` 只要滿足一筆即返回,且可利用索引。
低效:
SELECT DISTINCT d.dept_no, d.dept_name FROM dept d, emp e WHERE d.dept_no = e.dept_no
高效:
SELECT d.dept_no, d.dept_name FROM dept d WHERE EXISTS (SELECT 'X' FROM emp e WHERE e.dept_no = d.dept_no)
`EXISTS` 讓 RDBMS 核心在子查詢條件滿足瞬間返回,避免 `DISTINCT` 的排序去重開銷。
Oracle 解析器會將小寫轉大寫再執行。直接寫大寫 可省去轉換步驟(雖微小,但大量執行時可觀)。
`ORDER BY` 使用索引的嚴格條件:
若不滿足,改用 `WHERE` 過濾配合索引範圍掃描:
-- 低效:DEPT_TYPE 可為 NULL,無法用索引 SELECT dept_code FROM dept ORDER BY dept_type; -- 高效:利用索引範圍掃描 SELECT dept_code FROM dept WHERE dept_type > 0
低效:
SELECT job, AVG(sal) FROM emp GROUP BY job HAVING job IN ('PRESIDENT','MANAGER')
高效:
SELECT job, AVG(sal) FROM emp WHERE job IN ('PRESIDENT','MANAGER') GROUP BY job
`WHERE` 在分組前過濾,大幅減少參與分組的行數。
| 技巧 | 核心原則 | 效能影響 |
|---|---|---|
| 條件順序 | 連接先、強過濾後 | 減少中間結果集 |
| 避免 * | 明確列欄位 | 降低解析/字典查詢 |
| DECODE/CASE | 單掃描多邏輯 | 減少 I/O |
| TRUNCATE | 全表清空用 DDL | 極速、少資源 |
| 頻繁 COMMIT | 釋放鎖/Undo/Redo | 降低爭用 |
| 表別名 | 前綴所有欄位 | 加速解析、防歧義 |
| EXISTS > IN | 半連接、可用索引 | 避免子查詢全掃/排序 |
| EXISTS > DISTINCT | 早期終止 | 省去排序去重 |
| 大寫 SQL | 省轉換 | 微量累積效應 |
| WHERE > ORDER BY | 利用索引順序 | 避免排序操作 |
| WHERE > HAVING | 分組前過濾 | 縮小分組輸入 |