本文已獲原作者授權轉載。文章出自微信公眾帳號:老虎劉談SQL最佳化
作者介紹:老虎劉,原oracle 研發部門 Real-World Performance TEAM 成員,現在售後部門SSC專職做資料庫效能最佳化,主要為銀行、通訊、證券、製造等大型企業提供服務。
今天談談下面這幾個引數對資料庫效能和穩定性的影響:
cursor_sharing:遊標共享
_optim_peek_user_binds:繫結變數窺視
_optimizer_adaptive_cursor_sharing:自適應遊標共享(簡稱ACS),一般還包括另外兩個_optimizer_extended_cursor_sharing和_optimizer_extended_cursor_sharing_rel 引數)
_optim_peek_user_binds和ACS:
在10g,因為沒有ACS,一般建議客戶關閉繫結變數窺視功能的情況多一些。
在11g,很多客戶還是將繫結變數窺視和ACS都關閉了,原因有的是資料庫從1g升級而來,升級後沒有改,還有就是因為ACS早期版本有一些bug。其實這是兩個很好的引數,可以在程式碼寫的不是太好的情況下,也能獲得比較好的效能。雖然ACS可能還有一些小bug沒有解決(有的bug是在很特殊的情況下才會觸發),到了11204版本應該都不是大問題了。老虎劉建議還是都開啟比較好。
最重要的引數還在下面,如果做到了下面這兩點,上面兩個引數就顯得不是那麼重要了:
首先,cursor_sharing這個引數對系統效能和穩定性都非常重要,可惜經常被忽略,建議使用該引數的預設值:
即 cursor_sharing=EXACT (而不是FORCE或similar)
這要求應該使用繫結變數的地方,必須使用繫結變數。這個對於OLTP系統來說是鐵律,不容置疑,cursor_sharing=FORCE通常就是為了解決該使用繫結變數而沒有使用繫結變數的情況。前年在網上看到一個廣為流傳的某水果公司的AWR報告,居然設定 cursor_sharing= FORCE ,令人感嘆啊。
其次,還有一個重要的補充條件:
不該使用繫結變數的地方,不用繫結變數:對那些唯一值較少的欄位,特別是資料分佈不均的情況,不建議使用繫結變數。如type、status等欄位,我們建議使用常量:where type=1 and status=2。
這種情況如果使用了繫結變數,就是繫結變數窺視和ACS發揮作用的時候。
如果cursor_sharing=FORCE;或者cursor_sharing=EXACT,但是在資料分佈不均的欄位上也使用了繫結變數(兩者基本上是等同的,雖然後一種略好於前一種情況),那麼就要考慮“繫結變數窺視”和“自適應遊標”兩個引數的影響了。
看下面幾種情況:
1、關閉“繫結變數窺視”(預設是開啟):
ACS同時失效,這時系統的穩定性好(不會因為繫結變數的不同,發生執行計劃改變),但是整體效能會下降:因為不能窺視繫結變數,只能按照欄位是資料分佈均勻的情況來計算,在能否使用索引,返回行源的估值上,都會出現較大的偏差,有時可能會配合使用hint來提高SQL效能。
2、如果開啟了“繫結變數窺視”而不開啟ACS(預設是開啟):
那麼系統就會極不穩定:比如硬解析窺視到一個繫結變數適合全表掃描的執行計劃,不管接下來的繫結變數是否能使用索引,都會一直全表掃描下去,直到下次硬解析時再次窺視繫結變數才可能重新生成新的執行計劃。
3、如果開啟“繫結變數窺視”,同時開啟ACS:
這種情況在解決了一部分穩定性的同時,兼顧了效能。也是11g新增的ACS比10g沒有ACS進步的地方:執行計劃不再從一而終,而是會根據繫結變數的不同,不是很及時的做出調整:比如第一次窺視到的繫結變數適合全表掃描,那麼第二次即使使用的繫結變數適合走索引,也還是會使用全表掃描的執行計劃,下一次再次執行就會糾正為使用索引的執行計劃(具體請參考ACS的實現原理)。
繫結變數窺視和ACS這兩個引數是與直方圖資訊緊密聯絡在一起的,關閉直方圖收集,也就相當於關閉了繫結變數窺視和ACS,即使開啟了這兩個引數。
直方圖能較為準確的反映資料分佈不均欄位的資料分佈情況,一般使用預設選項(auto),某些特殊情況可以補充或去掉某些欄位的直方圖資訊。一些客戶在資料庫級關閉收集直方圖的做法是不建議的。
總結:
最佳實踐:
cursor_sharing=EXACT + 合理使用繫結變數(合理就是:類似ID、account_no等唯一值等於或接近錶行數的欄位,必須使用繫結變數;而type、status等唯一值少且數分別不均的欄位,不使用繫結變數)。
繫結變數窺視和ACS保持預設開啟狀態。
特殊情況:
1、欄位唯一值有一定的數量(介於少與多之間),比如1000個,如果資料分佈均勻,則可以使用繫結變數。如果欄位分佈不均,則把佔比多的幾個值,使用常量,其他值使用繫結變數。
2、欄位唯一值少,還有經常互相轉變的情況,比如常見的工單處理表:沒有處理的狀態是0,處理後的狀態是1,夜間統計資訊收集後,由於欄位值的不穩定,統計資訊經常不能反映表的實時資料分佈情況,這種情況談是否使用繫結變數已沒有意義,涉及這類表的SQL,可以關閉欄位上的直方圖收集,再配合rownum和hint 來提高SQL效率和穩定性,必要時還可以使用dynamic_sampling(動態取樣)來輔助最佳化器做出正確的執行計劃。
最差組合:
cursor_sharing=FORCE
_optim_peek_user_binds=TRUE(開啟繫結變數窺視)
_optimizer_adaptive_cursor_sharing=FALSE(關閉ACS,還有其他兩個引數也要一起設定)
執行計劃不穩定的同時還會帶來低效能。
以上言論僅代表個人,如與oracle公司文件衝突,以oraclce公司文件為準。如有不當之處敬請指正,提前感謝!