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

Oracle Hint 常用優化指南:從 ALL_ROWS 到 INDEX 讓執行計劃聽你的

     編輯:Oracle 資料庫基礎

前言

Oracle Hint (提示) 是開發人員與 DBA 影響優化器決策的「直接干預手段」。正確使用 Hint 能繞過優化器缺陷、穩定執行計劃、解決緊急性能問題。本文系統整理 12 類核心 Hint 的語法、適用場景、經典案例及**濫用風險警示**,助你精準施策。

優化目標類 Hint

Hint語法作用適用場景
ALL_ROWS/*+ ALL_ROWS */目標:最佳吞吐量 (最小化總資源消耗)。CBO 全表掃描、Hash Join、排序合併傾向。批處理、報表、數據倉庫、ETL、無用戶等待的後台作業。
FIRST_ROWS(n)/*+ FIRST_ROWS(10) */目標:最佳響應時間 (快速返回前 n 行)。CBO 傾向 Nested Loops、Index Range Scan、避免排序/全掃描。Web 分頁查詢、交互式應用、OLTP 核心交易 (n=1,10,100)。
CHOOSE/*+ CHOOSE */有統計信息用 CBO (ALL_ROWS),無統計信息用 RBO。**已廢棄 (10g+),勿用。**舊版遷移過渡期。
RULE/*+ RULE */強制使用基於規則優化器 (RBO)。**已廢棄 (10g+),勿用。**極少數 RBO 表現優於 CBO 的歷史系統 (極罕見)。

訪問路徑類 Hint

Hint語法作用適用場景與風險
FULL/*+ FULL(t) */對表 t 強制全表掃描。小表、無索引、統計信息缺失導致誤用索引、並行全掃描配合 PARALLEL。風險:大表災難。
ROWID/*+ ROWID(t) */強制通過 ROWID 訪問表 t (需先獲取 ROWID)。極少用,通常配合應用層緩存 ROWID。風險:ROWID 可能因行遷移/重組失效。
CLUSTER/*+ CLUSTER(t) */強制叢集掃描 (僅適用叢集表)。舊版叢集表極少見。
INDEX/*+ INDEX(t idx_name) */強制使用索引 idx_name 掃描表 t (Range/Unique/Full/Fast Full)。優化器誤判選擇性、跳過低選擇性索引、測試索引效果。**風險**:索引失效/不可用時報錯/全掃描。
NO_INDEX/*+ NO_INDEX(t idx_name) */禁止使用指定索引。索引導致計劃劣化、測試無索引基線。
INDEX_FFS/*+ INDEX_FFS(t idx_name) */索引快速全掃描 (不訪問表塊,僅掃描索引葉塊)。索引包含所有查詢欄位 (覆蓋索引)、統計信息準確。**需配合 INDEX_FILTER?**
INDEX_ASC / INDEX_DESC/*+ INDEX_DESC(t idx_name) */指定索引掃描方向 (避免排序)。ORDER BY pk DESC 配合索引降序掃描返回 Top-N。

連接方法類 Hint

Hint語法作用適用場景
USE_NL/*+ USE_NL(t2) */強制 Nested Loops Join (t2 為內表/驅動表)。小結果集驅動大表、內表有高選擇性索引、FIRST_ROWS 目標。
USE_HASH/*+ USE_HASH(t2) */強制 Hash Join。大表關聯、無合適索引、並行查詢、ALL_ROWS 目標。
USE_MERGE/*+ USE_MERGE(t2) */強制 Sort Merge Join。已排序數據源、大表關聯、並行查詢、Hash Join 記憶體不足。
LEADING/*+ LEADING(t1 t2 t3) */指定連接順序 (t1 驅動 t2,結果驅動 t3)。多表關聯優化器誤判驅動表、修復笛卡爾積風險。**最強連接控制 Hint。**
ORDERED/*+ ORDERED */按 FROM 子句順序連接。**不如 LEADING 靈活,勿用。**舊版兼容。
SWAP_JOIN_INPUTS/*+ SWAP_JOIN_INPUTS(t2) */交換 Hash Join 的 Build/Probe 輸入 (Build 端小表進內存)。優化器誤判 Build 端大小、並行 Hash Join 數據傾斜。

並行與其他實用 Hint

Hint語法作用
PARALLEL/*+ PARALLEL(t, 8) */指定表 t 並行度 8 (需 Enterprise Edition)。
NO_PARALLEL/*+ NO_PARALLEL(t) */禁止並行。
PQ_DISTRIBUTE/*+ PQ_DISTRIBUTE(t, HASH, HASH) */指定並行連接數據分發方式。
APPEND / APPEND_VALUES/*+ APPEND */直接路徑插入 (繞過緩存、高水位線、無重做最小化)。
NOLOGGING非 Hint,屬性。配合 APPEND 減少重做。大批量載入、中間表、可重建數據。
CARDINALITY/*+ CARDINALITY(t 1000) */告知優化器表 t 結果集基數 1000 行 (修正統計信息偏差)。
OPT_ESTIMATE/*+ OPT_ESTIMATE(TABLE t SCALE_ROWS=0.1) */11g+ 更強大的基數調整 (SCALE_ROWS, MIN/MAX, JOIN)。
DYNAMIC_SAMPLING/*+ DYNAMIC_SAMPLING(t 4) */級別 0-10,運行時採樣收集統計信息 (無統計/統計過期表)。
RESULT_CACHE/*+ RESULT_CACHE */結果集緩存 (11g+,需 RESULT_CACHE_MODE=FORCE 或 Hint)。
QB_NAME/*+ QB_NAME(main) */為查詢塊命名,供外層/其他 Hint 精準引用 (多層嵌套/視圖合併場景必須)。

經典實戰案例

案例 1:修復多表關聯笛卡爾積 (LEADING)

-- 原 SQL:A(2000行) JOIN B(15萬) JOIN C(18萬)
-- 優化器誤選 A-C Merge Join 產生 3.6億中間集
SELECT /*+ LEADING(a b c) USE_NL(b) USE_NL(c) */ a.*
FROM a, b, c
WHERE a.col_a = b.col_b1
  AND b.col_b2 = c.col_c;

解析:LEADING(a b c) 強制 A 驅動 B,再驅動 C。USE_NL 利用 B、C 上的索引。避免 A-C 直接關聯。

案例 2:深分頁優化 (FIRST_ROWS + INDEX_DESC)

SELECT /*+ FIRST_ROWS(10) INDEX_DESC(orders idx_orders_cust_date) */ *
FROM orders
WHERE cust_id = :cust_id
ORDER BY order_date DESC
FETCH FIRST 10 ROWS ONLY;

解析:FIRST_ROWS(10) 告知只需前 10 行。INDEX_DESC 利用 (cust_id, order_date DESC) 索引降序掃描直接返回,避免排序。

案例 3:大批量載入 (APPEND + PARALLEL)

INSERT /*+ APPEND PARALLEL(stg_sales, 8) */ INTO stg_sales
SELECT * FROM ext_sales_data;

解析:APPEND 直接寫數據塊 (高水位線以上),PARALLEL 多進程並行。配合 NOLOGGING 表屬性極速載入。

Hint 濫用風險與最佳實踐

  1. 綁定變量窺探失效:Hint 固定計劃,無法適應不同綁定值的選擇性差異。
    對策:僅在統計信息穩定、綁定值分布均勻、或配合 OPT_ESTIMATE 修正基數時使用。
  2. 統計信息更新後計劃不自動優化:Hint 強制舊計劃,錯過更優新計劃。
    對策:定期審視 Hint SQL,對比無 Hint 執行計劃,必要時移除/調整 Hint。
  3. Schema 變更導致 Hint 失效/報錯:索引重命名/刪除、表重命名。
    對策:DDL 變更流程必須掃描代碼庫中的 Hint 依賴。
  4. Hint 衝突:同一查詢塊同時指定 USE_NL 和 USE_HASH。優化器忽略衝突 Hint,行為不可預期。
    對策:代碼審查禁止多目標 Hint 共存。
  5. 過度依賴 Hint 掩蓋根因:索引缺失、統計信息缺失、SQL 寫法反模式。
    鐵律:**Hint 是止痛藥,不是治本藥。優先補統計、建索引、改 SQL、調參數,實在無解再用 Hint,並加註釋說明原因、預計移除時間。**

調試 Hint 生效狀況

-- 1. 10053 事件追蹤 (生成優化器決策日誌,含 Hint 採納/忽略原因)
ALTER SESSION SET EVENTS '10053 TRACE NAME CONTEXT FOREVER, LEVEL 1';
-- 執行 SQL
-- 關閉
ALTER SESSION SET EVENTS '10053 TRACE NAME CONTEXT OFF';

-- 2. V$SQL_PLAN.OUTLINE_DATA / OTHER_XML (11g+)
-- 查看實際執行計劃中體現的 Hint (OUTLINE 格式)

-- 3. DBMS_XPLAN.DISPLAY_CURSOR(FORMAT=>'OUTLINE')
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(sql_id, child_number, 'OUTLINE'));

結語

Oracle Hint 是「手術刀」,精準鋒利但風險自負。掌握 LEADING 控制連接順序、FIRST_ROWS/ALL_ROWS 設定目標、INDEX/NO_INDEX 控制訪問路徑、PARALLEL/APPEND 加速大數據操作、OPT_ESTIMATE/CARDINALITY 修正基數、QB_NAME 定位查詢塊 這幾大核心族群,建立 **Hint 使用登記表 (SQL_ID, Hint清單, 原因, 負責人, 評審日期, 移除計劃)**,在代碼審查、上線驗證、AWR 定期巡檢中強制執行「Hint 必審、必註、必評、必退」四字方針,才能讓 Hint 成為性能優化的加速器而非技術債的製造者。

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