為啥SQL Profile不起作用了,你知道嗎?
有個客戶前陣子一條SQL因為統計信息問題走錯執行計劃,導致CPU資源耗盡,系統出現嚴重故障,必須下線部分功能才臨時解決了問題,后來在開發商的嘗試下通過SQL PROFILE解決了錯誤執行計劃的問題,恢復了系統。事后遠程健康服務中心、Oracle原廠都參與了故障總結,都認為是因為統計信息不準導致了執行計劃錯誤。當時我也提出了一個更為徹底的解決方案,就是合并USERID和日期的兩個索引為復合索引,不過因為該表太大,開發商不太愿意重建索引,所以就沒有執行。
這個問題一般比較多的出在月底月初,只要產生了硬解析就容易出問題。自從加了SQL PROFILE也消停了一陣子。不過昨天又出問題了。
早上突然CPU飆升到100%,因為出過類似問題,所以很快就懷疑到了這條SQL上了。做個AWRSQRPT發現確實存在兩個執行計劃,又有SQL用錯索引了,似乎SQL PROFILE沒起作用了。
故障報到遠程健康服務中心的時候,我們的支撐人員建議他們用SQL PLAN BASELINE固化執行計劃,很快就恢復了系統。雖然問題解決的很快,不過用戶還是有些疑問,為什么上回出問題時候,研發部門采取的通過SQL PROFILE優化執行計劃的策略失效了。
實際上用戶是把SQL PROFILE當成綁定執行計劃了,其實從原理上講,SQL PROFILE并不是強行綁定執行計劃,而是通過SPM分析發現統計信息與實際運行情況不符,因此通過SQL PROFILE設置了一些TABLE_STATS hint,從而讓優化器可以使用更為精準的生成執行計劃。下面這張圖來自于Oracle的官方文檔,可以很好的解釋SQL PROFILE發揮作用的機理。
在SQL PROFILE提供的HINT中,并沒有指定執行計劃的內容,而只是設定了一些統計信息的糾正提示。因此設置了SQL PROFILE的SQL語句,SQL解析的時候,會使用PROFILE中的對象的統計信息來糾正執行計劃。這樣做的好處是靈活,比如某張表上的索引修改了。這條SQL解析的時候會考慮這些因素,選擇較好的執行計劃。不過也有不好的地方,那就是某些時候,執行計劃還是會錯誤。
SQL PROFILE是Oracle 10g引入的新功能,從11g開始,Oracle也看到了SQL PROFILE存在的不足,因此引入了一個新的功,SQL PLAN BASELINE。SQL PLAN BASE LINE的作用與SQL PROFILE類似,不過采取的方法完全不同。按照ORACLE官方文檔上的說法,SQL PLAN BASELINE是用于避免存在問題的執行計劃的。SQL PLAN BASELINE采取的是強行綁定執行計劃的方式。
上面這張圖也來自于Oracle的官方文檔,這張圖十分清晰,從上面我們可以看出,SQL PROFILE是用于糾正過去錯誤的執行計劃的,但是并不限定今后不會再次使用這個錯誤的執行計劃。而SQL PLAN BASELINE是用于確保以后不會使用錯誤的執行計劃的。
SQL PLAN BASELINE是一組可接受的計劃。每個計劃都使用一組Outline hint來實現,這些hint指定了特定的計劃。而與之不同的是,SQL PROFILE也使用hint實現,但這些hint沒有指定任何特定的計劃,僅僅糾正了優化器估算成本時產生的錯誤統計信息。
因為SQL PROFILE不會將優化器約束到任何一個計劃,所以SQL PROFILE比SQL PLAN BASELINE更靈活。初始化參數和優化器統計信息的更改使優化器能夠選擇更好的計劃。而SQL PLAN BASELINE一旦設定,那么今后這條SQL就只能使用一個固定的執行計劃了。當某條SQL根據綁定變量的不同會有多個不同的最優執行計劃的時候,SQL PROFILE可以充分發揮其靈活性。但是SQL PROFILE會有一定的出錯的可能性。
SQL PLAN BASELINE就簡單粗暴的多了,它是強制指定執行計劃。這對于某條SQL只有一個唯一的最優執行計劃的時候是最為有效的。不過它的缺陷是缺乏靈活性。
對于SQL PROFILE和SQL PLAN BASELINE,如果選擇錯誤,就很容易引發不可預知的隱患,因此需要十分謹慎的選擇。Oracle建議通過SPM的建議來選擇,而不要依靠DBA的自己判斷來選擇,從而避免錯誤使用。不過我覺得遇到類似問題,往往都和索引設計比較混亂有關,優化索引設計可以從更上游去解決此類問題。