說說生產系統索引的重建

realkid4發表於2011-07-26

 

在和運維兄弟們討論新系統運維規劃的時候,聊到了關於索引定期rebuild的問題。本篇也想發表一點筆者的拙見。

 

索引index是資料庫表進行最佳化搜尋的物件。索引與資料庫表的索引列取值在葉子節點上相對應,提供更為高效的搜尋執行計劃。索引的一個特性就是與資料表索引列的結構資料相對應。江湖上流傳,隨著資料表的增刪改操作,索引結構會呈現一種退化degrade趨勢,此時就需要定期進行索引的重建rebuild,來恢復索引的高效特性。

 

1、  Why to rebuild

 

索引結構本身是一個平衡B*樹,隨著對應資料錶行的增加修改和刪除操作,索引葉子節點會連帶發生變化,從而引起索引段結構的分裂、空置等變化。索引段index segment自身是一個不容易發生縮排的結構,所以索引本身呈現一個不斷脹大臃腫的趨勢。在對資料表進行DML操作的時候,索引樹要連帶進行變化。

 

ü        當進行insert操作時,一個非空的索引列值要插入到索引樹結構中,作為一個新的葉子節點。在這個過程中,Oracle要保證索引樹始終是平衡結構,要進行邏輯層面的分支節點分割,重新平衡過程。同時要進行物理塊的分割,保持葉子塊的相對寬鬆;

ü        當進行update操作時,Oracle索引同樣要進行一次deleteinsert相同的操作;

ü        當進行delete操作時,索引並不是將葉子節點回收,而是進行標記操作;

 

所以,對於一個經常進行DML操作的資料表而言,索引結構中往往包括了很多死葉子節點和分配未使用的空間。這種索引在表現上體現為資料行和索引對應塊數量的不匹配。那麼,僅僅因為這樣的索引,就需要我們經常性的進行索引rebuild。對索引進行瘦身處理嗎?

 

Oracle官方[MOS ID 989093.1]的角度看,週期性的index rebuild操作,將其作為日常運維的一部分是不必要的。通常而言,進行B*樹索引rebuild的場景是很少的,索引結構自身就是一個“self-managed, self-balanced”的結構。

 

通常我們認為索引需要經常性的rebuild,是基於下面的理由:

 

ü        頻繁的DML操作,引起index結構碎片化;

ü        索引段index segment結構膨脹,刪除deleted的葉子節點不會自己回收;

ü        聚簇因子clustering factor惡化;

 

事實上,在正常的DML操作下,索引結構是可以維持在一個相對臃腫的結構下。刪除的葉子節點的確會造成空間的浪費和檢索成本提高,但是刪除葉子節點是可以為下一次的insert/update操作所重用。而且被刪除的葉子節點遍佈整個葉子列表,為新資料值的插入提供了相當容納空閒空間。也就是說,雖然索引適度臃腫,但是這種臃腫不是空間的浪費,而是可被再次利用的。

 

聚簇因子衰弱的確是一個嚴重影響執行計劃的重要指標。但是聚簇因子的衰弱並不是由於索引結構自身問題,而是由於資料錶行排序順序的混亂造成的。解決聚簇因子退化的方法,是進行資料表重構,而非rebuild索引結構(關於clustering facter的相關內容,請參考筆者《Clustering Factor——索引的成本指標》http://space.itpub.net/17203031/viewspace-680936)。

 

綜合上述,筆者認為,正常DML情況下,週期性的對所有Index進行rebuild操作是不需要的。在資料表資料量維持穩定的情況下,適度臃腫的索引結構是我們可以接受的現實。

 

2Why not to rebuild

 

那麼,如果我們執意進行索引結構的定期rebuild,會帶來哪些風險呢?

 

首先,rebuild日常作業化容易帶來系統維護視窗的爭用。當我們進行rebuild索引結構時,給系統帶來一定程度的效能損耗和空間消耗。Rebuild索引必然會影響到前端業務系統的執行,選擇維護視窗期迴避業務高峰是唯一可以進行的折中。於是,rebuild又會影響到其他如統計量收集等更為重要的維護操作。

 

其次,重建的緊湊tight索引結構也許並不是適應DML操作的結構。緊湊的葉子節點意味著日後的DML操作要消耗很多資源來進行葉子塊拆分,空閒Free可用空間騰置。這對於“千辛萬苦”才培養成的適度臃腫的索引結構,是一個浪費。

 

最後,主流檢測索引語句的效能機制有問題。大部分檢測索引健康程度是建立在index_stats檢視下,使用analyze index XXX validate structure語句。但是這種方式在分析鎖的時候要獲取獨佔表table鎖。這是一個潛在的效能瓶頸。

 

綜合而言,確定日常性的索引rebuild操作是需要慎重的。要仔細進行分析和探討,做到消耗最少的資源,實現最優的效果。最起碼要做到索引的健全管理,有差異的rebuild

 

3what to rebuild

 

那麼,究竟什麼型別的索引需要進行索引定期rebuild呢?筆者認為,真正需要進行定期索引rebuild的索引在數量上是不多的,具體來說包括下面幾個型別。

 

ü        索引列呈現單向遞增順序,且DML頻繁,葉子節點空值重用率低的索引結構

 

我們上面的討論,有一個重要的思想,就是DML適度頻繁造成的索引葉子節點空值是不可怕的。因為葉子節點空值平均分佈在索引樹的葉子塊上,當有新的資料值來時,這些空值是可以被重用的。但是,一些索引列的變化呈現單向增長趨勢,如sequence列。索引列的新增數值都是單向增加關係,索引樹的擴充都是在索引樹一側進行分裂建立。如果說有刪除的空葉子節點,被新值利用的機率很低。這樣,索引樹就呈現出單向增加膨脹的趨勢。如果同時該資料表有定期就資料歸檔這種需求,就可以適當考慮進行索引定期重構事宜。

 

ü        診斷分析索引樹層次過高

 

索引樹的構成、維護演算法是複雜且帶有一定隨機特性的。作為樹狀結構的索引檢索優勢就在於平衡結構,從根節點開始,經過相同的比較和定位次數,都可以找到一個索引列取值的葉子節點。但是其中索引本身的層次level,也成為二元高度是索引健康程度的重要指標。一般的level高度不要超過三,如果我們分析一個關鍵索引的高度達到四或者是五層高度,那麼就真的需要進行重構較好。

 

ü        其他一些特殊情景

 

除了上述兩類,我們還要關注一些由於資料段物件本身原因引起的索引rebuild需要。比如,分割槽表的全域性索引在分割槽被刪除或者轉移之後,對應行rowid變化,全域性索引就需要rebuild,否則索引本身是失效unusable狀態。另一個場景是進行資料段本身的move操作,轉移表空間或者收縮高水位線HWM,對應的索引也會變為unusable狀態,這樣也需要對索引進行重建操作。

 

那麼,我們如何確定需要管理的索引範圍呢?

 

首先是確定DML頻繁資料表索引範圍,保持監控。資料表在系統中,活躍程度是不同的。讀多寫少型表的索引結構基本不需要管理(我們說通常的情況下),一次性的進行索引建立之後,發生變化的情況比較少,我們通常關注的力度稍稍弱些。對一些經常性發生DML操作的資料表,而且索引列是無規律變化的索引結構,我們最好在開發階段就應該主動將其識別出來,作為一份重要的維護列表進行定期健康檢查。

 

其次是先檢測索引健康程度,之後確定是否重建。索引的rebuild一定要是有標準的。我們首先透過DML頻繁程度和索引列形態,確定監控索引的優先順序別順序。之後,定期對關鍵操作索引進行監控,對監控出現問題的索引進行rebuild操作。採用監控的手段可以是analyze index XXX validate structure或者其他自定義工具。Rebuild備選依據可以是索引樹高度超高或者死葉子節點比例過高。

 

最後一些結構維護操作要考慮對索引結構的影響。如果我們進行move或者分割槽操作,一定要將對索引的影響考慮在其中。如果忽視這部分操作,會給將來效能帶來很大影響。

 

 

5、結論

 

索引的確是需要我們運維人員在系統執行過程中需要關注的一種重要內容。但是週期性的進行無差別索引重構的意義通常不是很大。筆者以為,還是要進行業務實際情況分析,明確一個經常性rebuild備選列表。之後進行索引列和實際情況分析,最後透過特定手段進行操作結構診斷,明確需要重構時,再進行重構操作較好。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-703166/,如需轉載,請註明出處,否則將追究法律責任。

相關文章