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