首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle SQL 效能調優 12 大核心原則:從 WHERE 順序到索引陷阱的實戰指南

     編輯:Oracle 資料庫基礎

兩大核心原則

  1. WHERE 子句條件順序(自下而上解析):表連接條件優先,過濾性最強的條件放最後(最靠近 WHERE 關鍵字)。主鍵等值條件 PK = ? 應置於末尾。
  2. 拒絕 SELECT *:解析階段需查資料字典展開所有欄位,增加開銷;網路傳輸、緩衝區、排序皆受影響。永遠明確列出所需欄位。

索引使用:優勢、代價與七大避坑指南

優勢

  • B-Tree 結構加速範圍/等值查詢,避免全表掃描。
  • 主鍵/唯一索引強制實體完整性。
  • 多表連結時大幅減少關聯成本。

代價

  • 額外儲存空間(約表大小 10~30%)。
  • 每次 DML 需同步維護索引(約 4~5 倍 I/O)。
  • 過多索引反而拖慢寫入、誤導優化器。

七大索引失效陷阱

#陷阱失效範例修正寫法原理
1索引列參與運算/函數WHERE sal * 12 > 25000WHERE sal > 25000/12函數導致無法使用索引範圍掃描
2隱式型別轉換落在索引列WHERE emp_type = 123 (emp_type 為 VARCHAR2)WHERE emp_type = '123' 或 TO_CHAR(emp_type) = '123'Oracle 內部轉換 TO_NUMBER(emp_type) 破壞索引
3IS NULL / IS NOT NULLWHERE dept_code IS NOT NULLWHERE dept_code >= 0 (數值) 或 WHERE dept_code IS NOT NULL (配合函數索引)單列索引不存 NULL,複合索引全 NULL 不存
4前導萬用字元 LIKEWHERE name LIKE '%abc%'改用 Oracle Text / Context 索引,或將條件前置 LIKE 'abc%'B-Tree 無法支援前導萬用字元
5NOT / != / <> 否定條件WHERE status != 'CLOSED'改寫為 WHERE status IN ('OPEN','PENDING') 或全表掃描否定條件選擇率通常極高,優化器傾向全表掃描
6複合索引未遵循前導列原則索引 (A,B,C) 查 WHERE B = 1 AND C = 2查詢必須包含前導列 A,或建立 (B,C) 索引索引樹按 (A,B,C) 排序,缺 A 無法定位
7資料傾斜導致優化器誤判狀態碼 99% 為 'A',查 WHERE status = 'B' 未用索引建立直方圖 METHOD_OPT => 'FOR COLUMNS SIZE SKEWONLY status'無統計資訊時優化器假設均勻分布

六大改寫技巧降低資源消耗

  1. EXISTS 替代 DISTINCT:
    -- 低效
    SELECT DISTINCT d.deptno, d.dname FROM dept d, emp e 
    WHERE d.deptno = e.deptno AND e.job = 'CLERK';
    
    -- 高效
    SELECT d.deptno, d.dname FROM dept d
    WHERE EXISTS (SELECT 1 FROM emp e WHERE e.deptno = d.deptno AND e.job = 'CLERK');
  2. UNION ALL 替代 OR(索引列):
    -- 低效
    SELECT * FROM loc WHERE loc_id = 10 OR region = 'TOKYO';
    
    -- 高效 (loc_id、region 均有索引)
    SELECT * FROM loc WHERE loc_id = 10
    UNION ALL
    SELECT * FROM loc WHERE region = 'TOKYO';
  3. UNION ALL 替代 UNION:避免排序去重開銷,業務允許重複時優先用 ALL。
  4. ORDER BY 掛載索引列/主鍵:ORDER BY pk_col 可直接利用索引順序,避免排序操作。
  5. WHERE 替代 HAVING:分組前過濾減少參與聚合的資料量。
    -- 低效
    SELECT job, AVG(sal) FROM emp GROUP BY job HAVING job = 'MANAGER';
    
    -- 高效
    SELECT job, AVG(sal) FROM emp WHERE job = 'MANAGER' GROUP BY job;
  6. 慎用子查詢,優先 JOIN:相關子查詢易導致 Nested Loops 暴增;改寫為 JOIN 或使用 WITH 子查詢因子化(物化)。

進階調優工具鏈

  1. EXPLAIN PLAN + DBMS_XPLAN.DISPLAY:查看執行計畫、成本、基數估算。
  2. SQL_TRACE + TKPROF:生產環境追蹤真實執行統計。
  3. DBMS_SQLTUNE / SQL Tuning Advisor:自動建議索引、改寫、統計資訊收集。
  4. V$SQL_PLAN、V$SQLSTATS:歷史執行計畫與統計對比。

實戰案例:一條 SQL 的優化過程

-- 原始:全表掃描、排序、臨時表
SELECT DISTINCT e.ename, d.dname
FROM emp e, dept d
WHERE e.deptno = d.deptno
  AND e.sal > (SELECT AVG(sal) FROM emp WHERE deptno = e.deptno)
ORDER BY e.ename;

-- 優化步驟:
-- 1. 子查詢因子化 (WITH)
-- 2. EXISTS 替代 DISTINCT
-- 3. 確保 deptno、sal 有索引
-- 4. 移除不必要的 ORDER BY (應用層排序)

WITH dept_avg AS (
    SELECT deptno, AVG(sal) AS avg_sal FROM emp GROUP BY deptno
)
SELECT e.ename, d.dname
FROM emp e
JOIN dept d ON e.deptno = d.deptno
JOIN dept_avg da ON e.deptno = da.deptno
WHERE e.sal > da.avg_sal
  AND EXISTS (SELECT 1 FROM emp e2 WHERE e2.deptno = e.deptno); -- 確保部門有員工
-- 執行計畫:NESTED LOOPS + INDEX RANGE SCAN,Cost 從 120 降至 15

總結

Oracle SQL 調優核心在於:理解優化器決策邏輯(CBO)、消除索引失效寫法、善用 EXISTS/UNION ALL/因子化改寫、以執行計畫為依據而非直覺。建立「寫 SQL → 看 Plan → 改寫 → 驗證」閉環習慣,並定期收集統計資訊、監控高耗 SQL,即能持續維持資料庫高效能運行。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved