開發期資料量小,SQL 寫法差異不明顯;上線後資料暴增,劣質 SQL 與優質 SQL 速度可差**百倍以上**。Oracle 以成本基礎優化器(CBO)為核心,**索引使用與否是性能分水嶺**。掌握優化器「拒絕索引」的規則,是寫出高效 SQL 的前提。
B-tree 索引**不儲存全 NULL 的索引鍵**。任何包含 `IS NULL` 或 `IS NOT NULL` 的條件,優化器**必走全表掃描**。
對策:業務允許時給預設值、建立函數式索引(`CREATE INDEX idx ON t(NVL(col, 'X'))`)、或改用位圖索引(低基數欄位)。
`WHERE first_name || ' ' || last_name = 'Bill Clinton'` → 索引失效。
對策:拆分條件 `WHERE first_name = 'Bill' AND last_name = 'Clinton'`;若為變數,應用層拆分後帶入。
`LIKE '%clinton%'` → 全表掃描。
`LIKE 'clin%'` → 可用索引範圍掃描。
對策:全文檢索、Oracle Text、或反轉欄位建索引(`REVERSE(col)`)。
`WHERE SAL * 12 > 25000`、`WHERE TO_CHAR(date_col, 'YYYY') = '2023'` → 索引失效。
對策:改寫為 `WHERE SAL > 25000/12`、`WHERE date_col BETWEEN DATE '2023-01-01' AND DATE '2023-12-31'`;必要時建函數式索引。
`WHERE status <> 'INVALID'` → 通常全表掃描。
對策:改寫為 `WHERE status < 'INVALID' OR status > 'INVALID'`(若有索引且選擇率高);或 `WHERE status IN ('VALID','PENDING')` 明確列舉正向值。
**結論**:`EXISTS` 通常更快,尤其子查詢結果集大、主查詢過濾後行數少時。`NOT EXISTS` 亦優於 `NOT IN`(後者需處理 NULL 三值邏輯)。
Oracle SQL 調優無銀彈,但**避開索引失效陷阱、善用 EXISTS/NOT EXISTS、控制排序、維護統計資訊、讀懂執行計畫**五大基本功,能解決 90% 以上效能問題。複雜案例再引入 Hint、Profile、Baseline、SQL Plan Management 等進階手段。