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

Oracle 索引不總是最優選:從 Clustering Factor 與 Filtering Factor 看執行計畫抉擇

     編輯:Oracle 資料庫基礎

核心觀念:Index Scan 不一定比 Full Table Scan 快

當 Oracle 在有索引的情況下選擇 Full Table Scan (FTS),通常不是優化器 Bug,而是基於成本估算 (Cost-Based Optimizer) 的理性決策。常見兩大原因:

  1. 統計資料缺失或過舊,導致 Cardinality 估算偏差。
  2. 依據實際資料分布與存取模式,FTS 確實比 Index Range Scan + Table Access by RowID 更低成本。

關鍵指標:Clustering Factor (CF) 與 Filtering Factor (FF)

Clustering Factor (CF) — 索引與表資料的排序一致性

  • 定義:掃描索引葉子塊時,對應需要讀取的**資料塊數量**期望值。
  • 理想情況:索引順序與表資料物理順序一致,CF ≈ 表區塊數 (Blocks)。
  • 惡化情況:大量隨機 INSERT/UPDATE 導致 RowID 跳躍,CF 可遠大於表區塊數,甚至接近行數 (Rows)。
  • 維護:ALTER INDEX idx_name REBUILD 或 REBUILD ONLINE 可重設 CF 接近理想值。

Filtering Factor (FF) — 查詢選擇率

  • 定義:WHERE 條件過濾後的結果集佔全表行數比例。
  • 由優化器根據統計資料 (Histogram、Min/Max、NDV) 估算。
  • FF 越小 (高選擇性),索引優勢越大;FF 越大 (低選擇性),FTS 優勢越大。

成本估算簡化模型

Index Access Cost ≈ FF × (CF + Index Blocks)
Full Table Scan Cost ≈ Table Blocks

當 FF × (CF + Index Blocks) > Table Blocks 時,優化器傾向 FTS。

實戰案例驗證 (Oracle 8.1.7 on HP)

測試表 MYTABLES:32.5 萬行,主鍵 MYID (1 ~ 409,654),CF > Table Blocks (因歷史大量 DML 導致)。

查詢 1:低選擇性 (FF ≈ 100%)

SELECT * FROM mytables WHERE myid >= 1;
  • 預估返回 31.8 萬行 (Card=318474)
  • 執行計畫:TABLE ACCESS FULL,Cost=3132,Physical Reads=19,828

查詢 2:高選擇性 (FF ≈ 1%)

SELECT * FROM mytables WHERE myid >= 400000;
  • 預估返回 663 行 (Card=663)
  • 執行計畫:INDEX RANGE SCAN (PK_MYTABLES) → TABLE ACCESS BY INDEX ROWID,Cost=346,Physical Reads=292

實務啟示

  1. 定期收集統計資料:DBMS_STATS.GATHER_TABLE_STATS,含 METHOD_OPT=>'FOR ALL COLUMNS SIZE AUTO' 建立直方圖。
  2. 監控 CF 變化:SELECT index_name, clustering_factor FROM user_indexes; 當 CF 明顯大於 Table Blocks 時排程 Rebuild。
  3. 撰寫 SQL 前估算 FF:粗略判斷回傳比例,若 > 5-10% 且無覆蓋索引,FTS 多半更優。
  4. 覆蓋索引 (Covering Index):將查詢欄位全部包含在索引中,可避免 Table Access by RowID,大幅降低 CF 影響。

下一篇將探討「函數索引與虛擬欄位」及「索引失效常見陷阱」。

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