Local index or Global index?

某物流客戶系統查詢快遞單的SQL,IO消耗爲TOP 1:
sql

SQL代碼以下:數據庫

select id,性能優化

       op_code,微信

       to_char(create_time, :"SYS_B_1") as create_time,oracle

       ……運維

  from T_EXP_OP_RECORD_CONTAINER  A 性能

  where status <> :"SYS_B_4" and  ID = :1 and rownum = :"SYS_B_5";優化


    其中T_EXP_OP_RECORD_CONTAINER 表是一個在Create_time字段按天一級分和op_code字段按地區二級分區的分區表,ID字段保存的是快遞單號信息,字段上存在索引。spa

    SQL代碼中出現了"SYS_B_n" 字樣的綁定變量,這是由於數據庫參數的cursor_sharging被設置爲FORCE(強烈建議保持默認值EXACT),SQL中使用的常量值被強制轉換成了綁定變量。rownum=後面的常量被強制轉換成了綁定變量,這個值根據常識能夠判斷爲1,由於只有1纔有意義。.net

    

    快遞單號基本上是惟一的,這樣的SQL,正常執行時間應該在1毫秒左右。


而下圖使用awrsqrpt收集的SQL實際執行狀況是:每次執行耗時1.236秒


SQL執行計劃以下:


    看到上面的執行計劃後,就會明白平均執行時間是1秒多就正常了:這個查詢要到6030個local index裏面檢索數據,平均每一個local index至少要掃描3個buffers 才能判斷記錄是否存在,由於有rownum=1 謂詞條件,最好的狀況是掃描local index的第一個分支就找到告終果,再也不繼續掃描下去;最差的狀況是掃描到local  index的最後一個分支才找到結果,或是沒有找到結果。


    通常狀況下,local index索引的使用,須要配合分區字段一塊兒作謂詞條件,才能只掃描少數的索引分支。而這個SQL因爲業務緣由,不能增長分區字段做爲謂詞條件。這種狀況就須要將local index改爲Global index,纔會使SQL性能達到最佳。


    可是,由於該表很是龐大(表和索引佔用的空間達到T級),須要按期刪除(轉移)歷史分區,只保留最近一年的數據,若是建立的是global index,刪除歷史分區後,須要對global index進行重建,維護時間窗口很難完成(有多個相似表)。這是個兩難的問題。

    

    針對快遞業務的特色,老虎劉給出的建議是:

一、仍使用local index,重建表,減小分區數量:按天分區改成按月分區,不要子分區;

二、由於不多有用戶會查詢1個月以上的快遞單,該表只保留最近2個月分區數據,其餘數據轉移到歷史分區,正常狀況只須要最多掃描2個分區,而不是原來的6030個分區

三、經過plsql實現查詢:當前分區沒有查詢到結果,再去查詢歷史分區。這樣也能保證超過2個月的快遞單也能正常查詢。


    總結:

    分區表,到底選擇global index仍是local index,須要根據具體的業務和運維的實際需求而定。不須要刪除歷史分區數據的分區表,能夠建立global index(如基礎數據表);須要按期刪除歷史分區的分區表,最好是建立local index,若是遇到分區字段沒法成爲查詢條件時,建議儘可能減小分區數,避免過多的local index 掃描,影響SQL性能。


關注「老虎劉談SQL優化」,分享老虎劉那些年的SQL優化案例!

腳本分享在QQ羣:16778072    

歡迎轉發分享給更多的朋友


爲了方便交流,有興趣的朋友能夠加入同名微信羣:



本文分享自微信公衆號 - 老虎劉談oracle性能優化(sql_tigerliu)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索