深入Oracle優化器 一條詭異執行計畫的解決之道

2021-09-02 20:32:17 字數 1343 閱讀 3174

摘要: cbo計算成本並選擇最佳執行計畫的至關重要輸入物就是表和索引的統計資訊,過舊或錯誤的統計資訊則可能導致乙個效能極差的執行計畫被錯誤地選中。本文將以乙個案例展示詭異的統計資訊如何影響執行計畫的生成。 1案例介紹 這是乙個簡單的sql,近兩個月來對於告警明細表(分割槽)做月度彙總查詢時,總是出現了異常緩慢的情況。

cbo計算成本並選擇最佳執行計畫的至關重要輸入物就是表和索引的統計資訊,過舊或錯誤的統計資訊則可能導致乙個效能極差的執行計畫被錯誤地選中。本文將以乙個案例展示詭異的統計資訊如何影響執行計畫的生成。

1案例介紹

這是乙個簡單的sql,近兩個月來對於告警明細表(分割槽)做月度彙總查詢時,總是出現了異常緩慢的情況。

測試sql:

20160505101224330.png

欄位nealarm_time是固定條件,欄位related_ems_cuid是不固定的(這些不固定條件的選擇性都不強),分割槽裁剪到的分割槽有著1~3月份的資料。

關於history_alarm表, 存放20150301至今的資料,每天大約150w資料,有按1天1分割槽、1個月1分割槽,第41個分割槽比較特殊,這是乙個有著2023年1月~3月份資料的分割槽;相信各位了解到這個sql的資料分割槽情況,第一聯絡到的訪問路徑就是分割槽全表掃瞄或訪問復合索引,畢竟訪問的資料佔據著1/3個分割槽的資料。

下面是執行計畫:

20160505101234374.png

該錶最新收集了表和索引的統計資訊,取樣比為auto,沒有收集直方圖,請看執行計畫可以注意到其中一些奇怪的細節:

1.索引his_alarm_index1預估基數比父節點回表的基數還小,而且小很多;

2.索引his_alarm_index1是乙個復合索引(nealarm_time,neend_time),訪問的字段只是日期(nealarm_time)

正常情況下,索引選擇率》=單錶選擇率,通過rowid回表後filter所返回的行數要小於索引掃瞄返回的行數;而如果訪問索引只是單純靠日期(nealarm_time)過濾資料,還要再回表,對於1/3分割槽資料多達1500w行,其成本代價是遠高於分割槽全表掃瞄的,這也難怪查詢如此緩慢。

從執行計畫上可以看到問題入手點:即id 3的索引預估返回值遠小於id 4單錶預估返回值,這是不合理的;再者即便要訪問索引,為什麼選擇了復合索引,而不是前導列同樣為nealarm_time的單字段索引?

210053看問題

為了弄清楚上一步分析後的疑問,我們收集10053 trace幫助解析cbo是如何根據統計資訊選擇執行計畫。

1. 首先計算單錶基數

20160505101250771.png

分割槽裁剪為part#:40,統計資訊來自分割槽統計資訊

單錶選擇率,沒有直方圖:

選擇率

優化一條UPDATE語句

最近見到一條開發人員寫的update語句,覺得沒什麼不對,可又覺得有地方不對,因為效能低下.update a set col2,col3 select col1,t from b where b.col1 a.col1 where exists select b.col1 from b where ...

一條sql 語句的優化

第二個版本 一條sql搞定,使用巢狀查詢,費時2 3分鐘 select a.indexid,c.title,c.createdtime,c.intro,d.picurl,e.src,e.size,e.info from mms content index a,mms index node b,mms...

Oracle獲取上一條記錄或上一條記錄函式

獲取上一條記錄,若沒有記錄則值為0,其中 lag news id,1,0 news id為根據哪乙個字段進行檢查,1 為每次偏移量,0 為沒有上一條時的返回值 select n.lag news id,1,0 over order by news id asc nid from news n 執行結...