SELECT * 強迫 Oracle 查詢 Data Dictionary 解析所有欄位名稱,增加解析開銷;且網路傳輸不必要資料。永遠明確列出需要的欄位。
每次 SQL 執行皆涉及:解析 → 優化 → 綁定 → 執行 → 擷取。批次處理、陣列擷取可大幅降低開銷。
-- 低效:多次往返
SELECT emp_name, salary FROM emp WHERE emp_no = 342;
SELECT emp_name, salary FROM emp WHERE emp_no = 291;
-- 次低效:游標迴圈 (仍多次 FETCH)
DECLARE CURSOR c1(p_no NUMBER) IS SELECT ... FROM emp WHERE emp_no = p_no;
BEGIN OPEN c1(342); FETCH ...; OPEN c1(291); FETCH ...; END;
-- 高效:單次查詢 (或使用 IN / UNION ALL)
SELECT a.emp_name, a.salary, b.emp_name, b.salary
FROM emp a, emp b
WHERE a.emp_no = 342 AND b.emp_no = 291;
參數調整:ARRAYSIZE (SQL*Plus/Forms/Pro*C) 建議設 200,增加每次擷取筆數。
單次掃描完成多條件聚合,替代多次查詢同一張表。
-- 低效:掃描 EMP 兩次
SELECT COUNT(*), SUM(sal) FROM emp WHERE dept_no = 20 AND ename LIKE 'SMITH%';
SELECT COUNT(*), SUM(sal) FROM emp WHERE dept_no = 30 AND ename LIKE 'SMITH%';
-- 高效:單次掃描
SELECT
COUNT(DECODE(dept_no, 20, 'X')) dept20_cnt,
COUNT(DECODE(dept_no, 30, 'X')) dept30_cnt,
SUM(DECODE(dept_no, 20, sal)) dept20_sal,
SUM(DECODE(dept_no, 30, sal)) dept30_sal
FROM emp WHERE ename LIKE 'SMITH%';
同理適用於 GROUP BY、ORDER BY。
將多個獨立查詢合併為單一查詢,減少 Parse/Execute 開銷 (代價:可讀性下降,需權衡)。
SELECT e.name, d.name, c.name
FROM cat c, dpt d, emp e, dual x
WHERE NVL('X', x.dummy) = NVL('X', e.rowid(+))
AND NVL('X', x.dummy) = NVL('X', d.rowid(+))
AND NVL('X', x.dummy) = NVL('X', c.rowid(+))
AND e.emp_no(+) = 1234
AND d.dept_no(+) = 10
AND c.cat_type(+) = 'RD';
DELETE FROM emp e
WHERE e.ROWID > (SELECT MIN(x.ROWID) FROM emp x WHERE x.emp_no = e.emp_no);
保留每組 emp_no 的第一筆 ROWID,刪除其餘。
DELETE:產生 Undo/Redo、觸發 Trigger、不釋放 High Water Mark、可 Rollback。TRUNCATE:DDL 隱含 Commit、不產生 Undo/Redo、瞬間釋放空間、重設 HWM、不可 Rollback、不觸發 DML Trigger。COMMIT 釋放:
警示:過度 Commit 破壞交易原子性 (All-or-Nothing),導致資料不一致。原則:在業務邏輯允許的最小原子單位 Commit (如:單筆訂單完成、批次處理每 1000 筆)。
| # | 反模式 | 最佳實踐 |
|---|---|---|
| 1 | SELECT * | 明確欄位清單 |
| 2 | 迴圈單筆 INSERT/UPDATE | 批次陣列綁定 / FORALL (PL/SQL) |
| 3 | WHERE 子句對欄位做函數運算 | 改寫條件或建立 Function-Based Index |
| 4 | 隱含資料型別轉換 | 明確 TO_DATE/TO_NUMBER/CAST |
| 5 | 未使用綁定變數 (Hard Parse 暴增) | 全面使用 Bind Variables |
| 6 | 缺乏統計資訊 (CBO 盲目優化) | 定期 DBMS_STATS.GATHER_* |
| 7 | 濫用 Hint 強制計畫 | 優先優化統計/索引/SQL 寫法,Hint 為最後手段 |
| 8 | 長交易未 Commit | 縮短交易範圍、適度 Commit |