在規則基礎優化器(RBO)模式下,Oracle 解析器遵循「從右到左」處理 FROM 子句表名,「自下而上」解析 WHERE 子句條件。掌握這兩大鐵律,是編寫高效 SQL 的基石。
原則:FROM 子句最右側表(Driving Table)最先被掃描並排序,故應將記錄數最少的表放在最後。
-- TAB1: 16,384 筆 | TAB2: 1 筆
-- 最佳:小表在右
SELECT COUNT(*) FROM tab1, tab2; -- 0.96 秒
-- 差勁:大表在右
SELECT COUNT(*) FROM tab2, tab1; -- 26.09 秒
三表以上連接時,選擇交叉表(Intersection Table)作為驅動表——即被其他表引用最多的表(如 EMP 連接 LOCATION、CATEGORY)。
Oracle 由下往上解析 WHERE 條件,因此:
-- 低效:先過濾 SAL > 50000,再跑子查詢
SELECT ... FROM emp e
WHERE sal > 50000
AND job = 'MANAGER'
AND 25 < (SELECT COUNT(*) FROM emp WHERE mgr = e.empno); -- 156.3 秒
-- 高效:先跑子查詢過濾 99% 資料,再檢查薪資職稱
SELECT ... FROM emp e
WHERE 25 < (SELECT COUNT(*) FROM emp WHERE mgr = e.empno)
AND sal > 50000
AND job = 'MANAGER'; -- 10.6 秒
SELECT * 強制 Oracle 查詢資料字典轉換欄位名,增加解析開銷。生產環境務必明確列出所需欄位,亦利於應用層與資料庫解耦。
每次 SQL 執行涉及解析、綁定、執行、獲取等多輪網路交互。將多次查詢合併為單次多表連接或 IN 列表,可大幅降低開銷。
-- 方法 1:兩次往返(最差)
SELECT ... FROM emp WHERE emp_no = 342;
SELECT ... FROM emp WHERE emp_no = 291;
-- 方法 2:游標循環(次差)
-- PL/SQL 迴圈仍需多次 FETCH
-- 方法 3:單次自連接(最佳)
SELECT a.emp_name, a.salary, a.grade,
b.emp_name, b.salary, b.grade
FROM emp a, emp b
WHERE a.emp_no = 342 AND b.emp_no = 291;
進階技巧:在 SQL*Plus / Pro*C 中設定 ARRAYSIZE 200,單次獲取更多行,減少網路交互。
RBO 時代的優化邏輯雖在 CBO(成本優化器)主導的現代版本中部分失效,但「小表驅動大表、強過濾後置、減少往返」的思想仍具普世指導意義,值得內化為肌肉記憶。