1. 程式人生 > >Oracle的索引分裂和索引維護(精)

Oracle的索引分裂和索引維護(精)

索引不是建好了就行了?難道還需要維護?帶著這個問題,開啟本篇部落格。
我們知道索引的資料結構是B樹,每次更新資料都會對索引進行更新,所以如果是一張訂單表,看起來這張表會一直在增長,並且訂單表會經受一定的高併發考驗(比如各種大促活動,秒殺活動)。對於開發人員來說,好像只對表操作就可以了,不用管oracle是如何做的,但實際上,若想清清楚楚、明明白白瞭解你寫的介面,只有業務邏輯可不行,必須深入去知道索引是如何更新、生產、分裂的,然後才能根據具體的業務,來維護合適的索引。你的程式慢,可能是因為這個問題。

索引分裂

根據B樹的理論,插入資料會使樹的結構經過旋轉已達到平衡,樹的平衡對於樹的查詢效率來說至關重要。好在資料結構的知識以及解決了這個問題。oracle的索引也一樣,當我們建立一個索引,並插入了100000行資料,這個插入的過程,oracle的索引是在隨時發生變化的。每個枝、葉所儲存的塊大小、數量也是可配置的。那麼索引是如何分裂的?
索引分裂有兩種形式:9-1分裂,5-5分裂。場景不同時,發生不一樣的分裂方式。

9-1分裂:絕大部分資料保留在舊節點上海,僅有非常小的一部分資料遷移到新節點。
5-5分裂:舊節點和新節點上的資料比例幾乎是持平的。

5-5分裂的觸發條件:

  1. 當樹的左側發生新值插入時(新值小於索引中的最大值)
  2. 發生DML操作,索引塊上沒有足夠空間分類新的ITL槽
  3. 新值所插入的索引塊上存在其他未提交的事務

5-5分裂看起來會讓索引變得虛胖。
2和3的發生概率和影響程度都很高,尤其當高併發事件時。

高併發

高併發時,插入操作過於集中在右側的索引塊上。對索引進行高併發優化的一個操作是建立反鍵索引,比如我們要儲存資料“10001”,“10002”,“10003”。這三個數很大機率會存在一個索引塊上,如果建立反鍵索引,以上資料就會變成“10001”,“20001”,“30001”,相當於把資料打散了。
細心的人會問,資料打散了,那本來我做範圍查詢就可以走INDEX RANGE SCAN就可以的,這樣一來豈不是要走INDEX FULL SCAN,降低查詢效率?沒錯。凡事有利有弊,索引應用反鍵索引最好做等值查詢,否則會增加I/O開銷。經過資料統計,反鍵索引有數倍於普通索引的效能提升(TPS),所以還是很值得考慮的。

索引維護

設計的再好的索引,經過考驗,特別是高併發的考驗後,也會變得效率低下。所以索引需要進行後期的優化。我們先來看為什麼會索引會變的效率低下。
索引的更新有三種操作:INSERT,UPDATE,DELETE。而索引的DELETE並不是實際刪除,執行DELETE後,知識將其內容清空,但節點還在(因為物理刪除一個樹的節點是很消耗資源的),當碎片多了以後,索引變得非常鬆散,會影響到索引的效能。

索引重建

條件:

  1. 索引樹高度過高,比如>=4
  2. 葉節點碎片過多,比如DEL_LF_ROWS/LF_ROWS>20%
  3. 葉節點使用率低下,比如PCT_USAGE<20%

笨方法:

  1. 分析索引結構
analyze index idx_test_id validate structure;
  1. 從index_stata中獲取我們要的資訊
select height,round((del_lf_rows_len/lf_rows_len)*100,2||'%' ratio,pct_used from index_stats where name='idx_test_id';

本方法之所以笨,因為第一步分析過程時間長,在分析的過程中會鎖表,線上系統幾乎不能忍受。
好方法:

通過估算

  • 估算出單個索引空間的儲存大小 INDEX_ROW_LEN = 10+COL_LEN
  • 索引塊可以儲存的索引數量(BLOCK_SIZE-192),192是資料庫保留部分。考慮預留比例,就是當索引數量超過索引塊一定大小時就會進行分裂,這個比例是PCTFREE儲存的。所以單個索引塊儲存索引的條目為(BLOCK_SIZE-192)*(1-PCTFREE)/INDEX_ROW_LEN
  • 計算索引的條目數,差不多等於行記錄數,但不一定。記為:NUM_INDEX_ROWS
  • 計算儲存這些資料需要多少個索引塊 NUM_INDEX_ROWS/((BLOCK_SIZE-192)*(1-PCTFREE)/INDEX_ROW_LEN)
  • 索引塊利用率為(1-上面這個大長式子)*100%

基於這個估算數可以評估索引塊利用率,判斷是否需要對索引進行重建。

索引重建

大致有兩種方式:重組和重建。又分為:線上和離線。
離線重組

alter index idx_test_id shrink space;

線上重組

alter index idx_test_id coalesce;
--(coalesce:聯合、合併)

離線重建

alter index idx_test_id rebuild;

線上重建

alter index idx_test_id rebuild online;

coalesce不會收回索引上的空閒空間,shrink space回收的也不徹底。所以比較好的折中方案是在空閒時間對索引進行線上重建,實質上是對錶進行重新掃描,重新建一個新的。