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

Oracle SQL 語句優化總結:從寫法到執行計畫的 20 條黃金法則

     編輯:Oracle 資料庫基礎

SQL 編寫層面優化

  1. 明確列出欄位,避免 SELECT *:減少網路傳輸、解析開銷、避免新增欄位導致應用錯誤。
  2. 使用綁定變數:WHERE id = :b1 而非字面值,促進游標共用、減少硬解析、防 SQL 注入。
  3. WHERE 條件順序:最優先寫等值連接條件 (JOIN),其次高選擇性過濾條件,最後低選擇性條件。優化器會自動重排,但良好順序利於閱讀與 Hint 生效。
  4. 避免隱性轉換:WHERE num_col = '123' 導致全表掃描,改為 WHERE num_col = 123 或 TO_NUMBER。
  5. 善用 EXISTS 替代 IN (子查詢):EXISTS 可在找到第一筆即停止,IN 可能物化子查詢結果集;NOT EXISTS 優於 NOT IN (後者含 NULL 時語意不同且效能差)。
  6. 避免在索引欄上使用函數/運算:WHERE TRUNC(date_col) = SYSDATE → 失效索引,改為 WHERE date_col >= TRUNC(SYSDATE) AND date_col < TRUNC(SYSDATE)+1。
  7. 使用 UNION ALL 替代 UNION:無需去重排序,效能差異巨大;業務允許重複時優先 UNION ALL。
  8. 分頁查詢優化:12c+ OFFSET ... FETCH NEXT ...;舊版用 ROW_NUMBER() OVER 或 ROWNUM 兩層嵌套,避免 ROWNUM 直接配合 ORDER BY 導致全排序。
  9. 合併多次掃描:DECODE/CASE 條件聚合、PIVOT/UNPIVOT、單次掃描計算多指標,減少 I/O。
  10. 刪除重複資料用 ROWID:DELETE FROM t WHERE ROWID > (SELECT MIN(ROWID) FROM t x WHERE x.key = t.key); 單語句、無需臨時表。

索引與存取路徑優化

  1. 索引選擇性原則:選擇性 > 95% (唯一/近似唯一) 最適合 B-Tree 索引;低選擇性考慮位圖索引 (僅 OLAP/數據倉庫) 或不建索引。
  2. 複合索引遵循「最左前綴」:INDEX (a,b,c) 支援 WHERE a=1、WHERE a=1 AND b=2、WHERE a=1 AND b=2 AND c=3,不支援 WHERE b=2。
  3. 覆蓋索引:查詢欄位全包含於索引中 (INDEX (a,b) INCLUDE (c) 12c+),避免回表 (Table Access by Index Rowid)。
  4. 外鍵必建索引:避免父表刪除/更新時全表掃描子表鎖定 (TM 鎖升級)。
  5. 定期重建/整理索引:ALTER INDEX ... REBUILD ONLINE 或 COALESCE,消除碎片、回收空間、更新統計資訊。
  6. 監控未使用索引:ALTER INDEX ... MONITORING USAGE → USER_OBJECT_USAGE,長期未用者評估刪除。

執行計畫與統計資訊

  1. 收集具代表性的統計資訊:DBMS_STATS.GATHER_TABLE_STATS(..., METHOD_OPT=>'FOR ALL COLUMNS SIZE AUTO'),直方圖自動識別傾斜欄位。
  2. 鎖定穩定計畫:DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE 建立 SQL Plan Baseline,防止統計變動導致計畫突變。
  3. 使用 DBMS_XPLAN.DISPLAY_CURSOR 觀察實際執行計畫:關注 E-Rows vs A-Rows、Cost、Access Predicates/Filter Predicates、Pstart/Pstop (分區裁剪)。
  4. 善用 Hint 但謹慎:/*+ INDEX(t idx_name) */、/*+ LEADING(t1 t2) */、/*+ OPT_PARAM('_optim_peek_user_binds','false') */ 等,作為臨時干預,長期靠統計與 Baseline。
  5. 定期 AWR/ASH 分析 Top SQL:建立基線、對比趨勢、針對性優化而非全盤掃描。

架構與參數層面

  1. 大表分區:Range/Interval/List/Hash/Reference/Composite 分區,實現分區裁剪、分區級維護、分佈式平行查詢。
  2. 物化視圖重寫:CREATE MATERIALIZED VIEW ... ENABLE QUERY REWRITE,預聚合、預聯結,透明加速報表查詢。
  3. 結果快取:RESULT_CACHE_MODE = FORCE 或 Hint /*+ RESULT_CACHE */,適用於頻繁查詢、低更新頻率的參考表。
  4. 調整優化器參數:OPTIMIZER_MODE、OPTIMIZER_INDEX_COST_ADJ、OPTIMIZER_INDEX_CACHING、CURSOR_SHARING,需在測試環境驗證後再上線。

經典反模式與修正

反模式問題修正
WHERE col LIKE '%abc%'前導萬用字元導致全表掃描Oracle Text / 反向鍵索引 / 應用層前綴搜尋
SELECT DISTINCT * FROM huge_table大量排序/雜湊去重業務確認是否必要、改用 GROUP BY、增加唯一索引
隱性轉換 WHERE num = '123'索引失效、計畫錯誤應用層修正資料型別、或建立函數索引 TO_NUMBER(col)
長交易不提交Undo 膨脹、鎖爭用、Snapshot Too Old拆分批次、頻繁 Commit、調整 UNDO_RETENTION
游標未關閉 (應用層)ORA-01000、Library Cache 壓力連線池配置 maxOpenPreparedStatements、代碼審查 finally 關閉

優化檢查清單 (上線前自檢)

[ ] 是否使用綁定變數?
[ ] 是否避免 SELECT *?
[ ] WHERE 條件是否利用索引 (無函數/運算/隱性轉換)?
[ ] 是否收集最新統計資訊 (含直方圖)?
[ ] 執行計畫是否符合預期 (無全表掃描、無笛卡爾積)?
[ ] 是否有排序/雜湊操作溢寫磁碟 (PGA 足夠?)
[ ] 大表是否分區/平行?
[ ] 是否有 Baseline 保護關鍵 SQL?
[ ] 索引是否過多/未使用/碎片化?
[ ] 應用層是否正確關閉游標/連線?

SQL 優化是「寫對語法 → 建對索引 → 收好統計 → 看懂計畫 → 鎖定計畫 → 持續監控」的工程循環。沒有萬能銀彈,只有針對具體負載、數據分佈、業務容忍度的持續微調。

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