Oracle的索引分裂和索引維護(精)
索引不是建好了就行了?難道還需要維護?帶著這個問題,開啟本篇部落格。
我們知道索引的資料結構是B樹,每次更新資料都會對索引進行更新,所以如果是一張訂單表,看起來這張表會一直在增長,並且訂單表會經受一定的高併發考驗(比如各種大促活動,秒殺活動)。對於開發人員來說,好像只對表操作就可以了,不用管oracle是如何做的,但實際上,若想清清楚楚、明明白白瞭解你寫的介面,只有業務邏輯可不行,必須深入去知道索引是如何更新、生產、分裂的,然後才能根據具體的業務,來維護合適的索引。你的程式慢,可能是因為這個問題。
索引分裂
根據B樹的理論,插入資料會使樹的結構經過旋轉已達到平衡,樹的平衡對於樹的查詢效率來說至關重要。好在資料結構的知識以及解決了這個問題。oracle的索引也一樣,當我們建立一個索引,並插入了100000行資料,這個插入的過程,oracle的索引是在隨時發生變化的。每個枝、葉所儲存的塊大小、數量也是可配置的。那麼索引是如何分裂的?
索引分裂有兩種形式:9-1分裂,5-5分裂。場景不同時,發生不一樣的分裂方式。
9-1分裂:絕大部分資料保留在舊節點上海,僅有非常小的一部分資料遷移到新節點。
5-5分裂:舊節點和新節點上的資料比例幾乎是持平的。
5-5分裂的觸發條件:
- 當樹的左側發生新值插入時(新值小於索引中的最大值)
- 發生DML操作,索引塊上沒有足夠空間分類新的ITL槽
- 新值所插入的索引塊上存在其他未提交的事務
5-5分裂看起來會讓索引變得虛胖。
2和3的發生概率和影響程度都很高,尤其當高併發事件時。
高併發
高併發時,插入操作過於集中在右側的索引塊上。對索引進行高併發優化的一個操作是建立反鍵索引,比如我們要儲存資料“10001”,“10002”,“10003”。這三個數很大機率會存在一個索引塊上,如果建立反鍵索引,以上資料就會變成“10001”,“20001”,“30001”,相當於把資料打散了。
細心的人會問,資料打散了,那本來我做範圍查詢就可以走INDEX RANGE SCAN就可以的,這樣一來豈不是要走INDEX FULL SCAN,降低查詢效率?沒錯。凡事有利有弊,索引應用反鍵索引最好做等值查詢,否則會增加I/O開銷。經過資料統計,反鍵索引有數倍於普通索引的效能提升(TPS),所以還是很值得考慮的。
索引維護
設計的再好的索引,經過考驗,特別是高併發的考驗後,也會變得效率低下。所以索引需要進行後期的優化。我們先來看為什麼會索引會變的效率低下。
索引的更新有三種操作:INSERT,UPDATE,DELETE。而索引的DELETE並不是實際刪除,執行DELETE後,知識將其內容清空,但節點還在(因為物理刪除一個樹的節點是很消耗資源的),當碎片多了以後,索引變得非常鬆散,會影響到索引的效能。
索引重建
條件:
- 索引樹高度過高,比如>=4
- 葉節點碎片過多,比如DEL_LF_ROWS/LF_ROWS>20%
- 葉節點使用率低下,比如PCT_USAGE<20%
笨方法:
- 分析索引結構
analyze index idx_test_id validate structure;
- 從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回收的也不徹底。所以比較好的折中方案是在空閒時間對索引進行線上重建,實質上是對錶進行重新掃描,重新建一個新的。