1. 程式人生 > >一個執行計劃異常變更的案例

一個執行計劃異常變更的案例

今天快下班的時候,幾位兄弟來聊一個問題,大致是昨天應用使用的資料庫突然出現效能問題,DBA發現有一些delete語句執行時間驟長,消耗大量系統資源,導致應用響應時間變長積Q。目前掌握的資訊如下:
(1) 應用已經很久未做過更新上線了。
(2) 據開發人員反饋,從之前的應用日誌看,未出現處理時間逐步變長的現象。
(3) 這是一套RAC+DG的環境,版本未知,猜測至少應該是11g的版本。
(4) 這次突然出現大量執行時間超長的SQL語句,是一系列delete語句,例如delete from table where key=:1or key=:2 … key=:13這種SQL,應用正常的處理邏輯中都會使用這條語句,因此併發較高,使用了繫結變數,key欄位不是主鍵,但有索引。目前尚不知曉欄位是否存在直方圖。
(5) 表的資料量大約5000萬,初步反饋得知key=0的記錄大約1500萬,執行時間超長的SQL語句都使用了key=0的條件,至於key=0的真實資料量,以及出現問題的SQL語句使用的繫結變數具體值,這些還需要開發再次確認。
(6) DBA反饋SQL語句執行計劃發生了變化,從資料庫層面做了一些操作後,問題解決,目前尚不知曉做了什麼具體的操作。

之所以這篇文章標題是“前傳“,是因為現在已知的上述資訊很有限,不能給出非常明確的出錯原因,需要明日進一步和開發以及DBA瞭解後才能做深入的分析,瞭解真正的問題根源。

這裡想說的什麼情況下可能造成SQL執行計劃發生改變?有很多種情況,這裡拋磚引玉舉一個例子。再次宣告,以下實驗和上面的問題可能沒有直接關係,僅是引申的一些觀點,上面問題的根源還有待進一步確認和排查。

實驗:
建立測試表t1,其中name欄位設定索引,取值為10000個A和1個B。
這裡寫圖片描述

我們看下用查詢條件name=’A’的SQL使用了什麼執行計劃,
這裡寫圖片描述

再看下使用查詢條件name=’B’的SQL用了什麼執行計劃,
這裡寫圖片描述
這裡寫圖片描述

顯而易見,因為取值為A的記錄佔據了10000/10001接近100%的比重,即這查詢條件返回了幾乎表的所有資料,使用全表掃描的成本一般會小於使用索引的成本,由於TABLE ACCESS FULL會掃描表高水位線以下的資料塊,且為多塊讀,即一次IO會讀取多個數據塊,具體資料塊數量取決於引數db_file_multiblock_read_count,而INDEX RANGE SCAN則是單塊讀,同時若select欄位不是索引欄位的話,還需要回表,累積起來,IO次數就會可能很大,因此相比起來,全表掃描的IO可能會遠小於索引掃描。

取值為B的記錄佔據了1/10001很小的比重,因此使用索引掃描,直接訪問B*Tree二叉樹,定位到這一條資料的rowid再回表查詢所有select欄位的成本要遠小於掃描整張表資料的成本。

為了證明,可以檢視這兩條SQL對應的10053事件,如下是name=’A’的trace,可以看出全表掃描的成本值是49.63,索引掃描的成本值是351.26,全表掃描的成本更低一些。
這裡寫圖片描述

如下是name=’B’的trace,可以看出全表掃描的成本值是49.40,索引掃描的成本值是2.00,索引掃描的成本值更低一些。
這裡寫圖片描述

這個場景可以看出,Oracle的CBO模式會根據欄位的取值比重調整對應的執行計劃,無論如何,都會選擇成本值最低的一個執行計劃,這也是CBO優於以前RBO的地方,這裡僅用於實驗,因為一般OLTP的應用會使用繫結變數的寫法,不會像上面這種使用常量值的寫法,11g之前,可能帶來的一些負面影響就是繫結變數窺探的作用,即對於使用繫結變數窺探的SQL語句,Oracle會根據第一次執行使用的繫結變數值來用於以後的執行,即第一次做硬解析的時候,窺探了變數值,之後的軟解析,不再窺視,換句話說,如果上面實驗的SQL語句使用了繫結變數,第一次執行時name=’A’,則接下來即使使用name=’B’的SQL語句仍會使用全表掃描,不會選擇索引掃描,vice versa。相關的實驗dbsnake的書中會有很詳細的說明,可以參考。11g之後,有了ACS自適應遊標的新特性,會根據繫結變數值的情況可以重新生成執行計劃,因此這種問題得到了緩解,當然這些都是有代價的,緩解了繫結變數窺探的副作用,相應地可能會導致有很多子游標,具體的演算法可以參考dbsanke的書,這兒我就不班門弄斧了。11g預設繫結變數窺探是開啟的,由以下隱藏引數控制,
這裡寫圖片描述

綜上所述,針對這場景,如果值的選擇性顯著影響執行計劃,則繫結變數的使用並不可靠,此時選擇字面值的方式可能會更合適一些,如果值的選擇性幾乎相同,執行計劃不會顯著改變,此時使用繫結變數是最優的選擇,當然前提是OLTP系統。

對於多次執行SQL語句,執行計劃發生變化的情況可能還有很多,例如11g的新特性Cardinality Feedback帶來的一些bug,包含直方圖的欄位作為查詢條件但統計資訊不準(dbsnake的書中有一個案例)等,有機會做一些實驗,再呈現出來。

至於本文開始提到的這個問題,進一步瞭解相關資訊後,可以詳細地介紹下。