Oracle 12C優化器的巨大變化,上生產必讀(上)
2、自適應計劃
3、自適應的連線方式
在執行的時候,統計收集器收集了關於這次執行的資訊,並且將一部分進入到子計劃的資料行快取起來。在這個例子中,統計收集器監控並快取了對order_items的全表掃描。基於它在統計收集器中看到的資訊,優化器會最終確定採用哪個子計劃。在這個例子中,雜湊連線被選為最終計劃,因為來自order_items表的行數大於優化器最初的估計。
在優化器選擇了最終計劃之後,統計收集器停止收集統計資訊以及對資料行的快取,而僅僅是傳遞資料。在子游標隨後的執行中,優化器禁止了資料快取,並且選擇了同一個最終計劃。目前的優化器能夠從巢狀連線切換到雜湊連線,反之亦然。可是,如果初始選中的連線方法是排序合併連線,則自適應不會發生。
(圖2. 自適應執行計劃確定Order_items 和 Prod_info 表之間的連線)
在預設情況下,explain plan命令只會顯示優化器選定的初始(預設)計劃。而DBMS_XPLAN.DISPLAY_CURSOR只顯示查詢所用的最終計劃。
(圖3. Explain plan 和 DBMS_XPLAN.DISPLAY_CURSOR 為圖2的查詢例子所輸出的計劃)
為了看到自適應計劃中所有的操作,包括統計收集器的位置,你必須在DBMS_XPLAN函式中指定額外的格式引數’+adaptive’。在這個模式下,id欄會出現一個額外的(-)記號,指明在計劃中未被採用(非啟用)的操作。在ORACLE企業管理器(OEM)中的SQL監控工具總是顯示完整的自適應計劃,但是並沒有指明在計劃中的哪些操作是非啟用的。
(圖4. 在DBMS_XPLAN.DISPLAY_CURSOR中使用’+adaptive’格式引數得到的完整自適應計劃)
V$SQL中增加了一個新的列(IS_RESOLVED_ADAPTIVE_PLAN)來指明一個SQL語句是否有自適應計劃,以及該計劃是否已經完全被確定。如果IS_RESOLVED_ADAPTIVE_PLAN被設定為’Y’, 這意味著計劃不僅是自適應的,而且最終計劃已被選定。可是,如果IS_RESOLVED_ADAPTIVE_PLAN被設定為’N’, 這指明瞭選定的計劃是自適應的,但是最終計劃仍未被確認。’N’值僅僅在一個查詢的初始執行階段中可見,在此之後,自適應計劃的這個值總是為’Y’。對於非自適應計劃這個列被設定為NULL。
你也可以通過將初始化引數OPTIMIZER_ADAPTIVE_REPORTING_ONLY設定為TRUE(預設值是FALSE),從而把自適應連線方式置於報告模式。在這個模式下,開啟自適應連線方式所需的資訊會被收集,但是改變計劃的任何動作都不會發生。這意味著預設計劃總是會被採用,但是關於計劃在“非報告”模式下會如何調整的資訊將被收集。這個資訊可以在自適應計劃的報告中被檢視,當你用額外的格式引數’+report’顯示計劃的時候就可以看到。
(圖5. 在DBMS_XPLAN.DISPLAY_CURSOR中使用’+report’格式引數所顯示的完整自適應報告)
4、自適應並行分配方法
當一個SQL語句以並行模式執行時,某些特定操作,例如排序,聚合和連線,它們要求在執行語句的並行服務程序之間重新分配資料。優化器所用的分配方法取決於操作型別,涉及到的並行服務程序數,以及預期的行數。如果優化器對行數估算不準確,那麼選中的分配方法就可能不理想,結果某些並行服務程序就可能得不到充分利用。
隨著新的自適應分配方法”混合型雜湊”(HYBRID HASH)的引入,優化器可以將分配方法的確定延遲到執行的時候才確定,此時它對於涉及到的資料行數就有了更多的資訊。一個統計收集器被插入到操作的前面,如果快取的資料的實際行數比閾值小,則分配方法將從雜湊(HASH)切換到廣播(BROADCAST)。然而,如果緩衝的行數達到了閾值,則分配方法將會是雜湊(HASH)。閾值的定義為並行度的兩倍。
圖6顯示了SQL監控工具中的一個執行計劃的例子,它是一個以並行模式執行的EMP和DEPT表之間的連線。一組並行服務程序(生產者,即粉紅色圖示)掃描兩個表並且將資料送給另一組並行服務程序(消費者,即藍色圖示),該組程序是連線的真正執行者。優化器決定採用混合型雜湊(HYBRID HASH)的分配方法。在這個連線中訪問的第一個表是DEPT表。來自DEPT表的資料行被快取在統計收集器中,見計劃的第六行,直至閾值被超越,或者最後一行被獲取。在那時優化器將會決定採用何種分配方法。
(圖6. SQL監控工具中的一個EMP和DEPT表之間的連線的執行計劃,它使用了自適應分配方法)
我們假定這個例子中的並行度被設定為6, 從DEPT表掃描返回的行數是4, 閾值則是12行(2X6)。既然還未達到閾值,從DEPT表返回的4行將會被廣播到負責完成連線的6個並行服務程序,結果計劃中的分配步驟所處理的行數是是24行(4X6),見圖7。
既然對於來自DEPT表的資料行採用了廣播(BROADCAST)的分配方法,來自EMP表的資料行將會通過迴圈制(ROUND-ROBIN)的方法進行分配。這意味著來自EMP表的一行資料將會輪流傳送給6個並行服務程序中的一個,直至所有的資料行都分配完畢。
(圖7. 混合型雜湊分配法使用廣播的分配方式,因為未達到閾值)
可是,如果這個例子的並行度被設定為2, 而掃描DEPT表返回的行數為4, 則閾值為4行(2X2)。既然已經達到了閾值,從DEPT表返回的4行資料將會以雜湊(HASH)的方式分配到負責完成連線的2個並行服務程序, 結果計劃中的分配步驟所處理的行數是是4行(見圖8)。既然來自DEPT表的資料行採用了雜湊(HASH)分配法,來自EMP表的資料也會以雜湊(HASH)方法進行分配。
(圖8. 混合型雜湊分配法使用雜湊的分配方式,因為已達到閾值)
5、自適應統計資訊
6、動態統計資訊
在Oracle 12c資料庫中, 動態取樣被強化為動態統計資訊。動態統計資訊允許優化器強化現有的統計資訊以獲取更加精確的基數估算,不僅僅是為單表的訪問,而且也包含連線和分組(GROUP BY)謂詞。初始化引數OPTIMIZER_DYNAMIC_SAMPLING引入了新的取樣級別11。11級使得優化器能夠自動為任何SQL語句使用動態統計資訊,即使所有基本的表統計資訊都已經存在。優化器做出使用動態統計的決定,是基於所用謂詞的複雜性,和已經存在的基礎統計資訊,以及預期的SQL語句總執行時間。例如,之前的優化器在某些情況下會使用猜測的方法,比如帶有LIKE謂詞和模糊匹配的查詢,而現在則會啟用動態統計資訊。
(圖9. 當 OPTIMIZER_DYNAMIC_SAMPLING 被設為級別 11,動態取樣會被使用,而不是猜測)
在這些新的條件下,當級別設定為11時,動態取樣啟用的頻率很可能超過以往。這會增加語句的解析時間。為了將對效能的影響減到最低,動態取樣查詢的結果將會作為動態統計資訊保留在快取中,允許其他SQL語句來共享這些統計資訊。SQL計劃指令(下面將會更詳細地討論)也會利用這種級別的動態取樣。
7、自動重優化
8、統計資訊反饋
在查詢結束之時,優化器將它原來的基數估算和在執行期間觀測到的實際基數進行比較,如果估算值和實際值有顯著差異,它會將正確的值儲存起來供後續使用。它還會建立一個SQL計劃指令,使得其他的SQL語句也能受益於這次初始執行中學到的資訊。如果查詢再次執行,優化器會使用糾正過的基數估算值,而不是它原先的估算值,來確定執行計劃。如果它發現初始的估算值是正確的,則不會採取任何額外的措施。在第一次執行之後,優化器關閉了統計資訊反饋的監視。
圖10顯示了一個SQL語句受益於統計資訊反饋的例子。在這個兩表連線的初次執行中,由於customers表上有多個相關的單列謂詞,優化器將基數低估了8倍。
(圖10. 一個受益於自動重優化的統計資訊反饋的SQL語句初次執行的情況)
在初次執行之後,優化器將它原來的基數估算和計劃中的操作實際返回的行數進行比較。估計值和實際返回的行數有很大的差別,所以這個遊標被標記為IS_REOPTIMIZIBLE(可重優化)並且不會被再次使用。IS_REOPTIMIZIBLE屬性指明這個SQL語句應該在下一次執行的時候被硬解析,所以優化器能夠使用在初次執行時記錄下來的統計資訊來確定一個更佳的執行計劃。
(圖11. 在初次執行的統計資訊與原有的基數估算有顯著差異之後,遊標被標識為可重優化)
一個SQL計劃指令同樣被建立,這是為了確保下次如果在customers表使用了相似的謂詞的SQL語句被執行,優化器會注意到這些列之間的相關性。
在第二次執行,優化器使用了來自初次執行的統計資訊來確定一個具有不同連線順序的新計劃。在生成執行計劃的過程中對統計資訊反饋的使用情況被註明於執行計劃下面的備註部分。
(圖12. 新生成的計劃使用來自初次執行的統計資訊)
新計劃沒有標識為IS_REOPTIMIZIBLE,所以它將被這個SQL語句的所有後續執行所使用。
(圖13. 新生成的計劃標識為不可重優化)
9、效能反饋
(圖14. 一個SQL語句的執行計劃,效能反饋發現它序列執行會更好)
10、SQL計劃指令
(圖15. 一個語句所使用的SQL計劃指令數目被顯示於執行計劃下方的備註部分)
資料庫自動維護SQL計劃指令,並把它們儲存在SYSAUX表空間。任何未被使用的SQL計劃指令在53周之後會被自動清除。SQL計劃指令也可以通過DBMS_SPD包手動管理。然而,你不可能手動建立一個SQL計劃指令。SQL計劃指令可以通過檢視DBA_SQL_PLAN_DIRECTIVES和DBA_SQL_PLAN_DIR_OBJECTS進行監控(見圖16)。
如前所述,當圖10所示的SQL語句被發現優化器的基數估算和計劃中的操作所返回的實際行數有顯著差異時,一個SQL計劃指令就被建立。實際上,有兩個SQL計劃指令被自動建立。一個是為了糾正在customers表上由於多個單列謂詞之間的相關性所導致的基數估算偏差,一個是為了糾正sales表上的基數估算偏差。
(圖16. 檢視根據通過自動重優化學習到的資訊所創建出來的SQL計劃指令)
在目前僅有一種型別的SQL計劃指令,即”動態取樣(DYNAMIC_SAMPLING)”。這會告訴優化器,如果看到了這個特定的查詢表示式(例如,在country_id, cust_city, 和 cust_state_province上一起使用的過濾謂詞),它就應該使用動態取樣來糾正基數估算的偏差。
SQL計劃指令同樣被ORACLE用來確定擴充套件統計資訊(特別是列群組)是否缺失,是否基數估算偏差能被列群組所糾正。如果是這樣的話,它會在下一次收集統計資訊的時候自動在相應的表上建立那個列群組。於是如果可能的話,擴充套件資訊就會取代SQL計劃指令被使用在SQL計劃中(等值謂詞,group by分組等等)。如果SQL計劃指令已經沒必要存在,它會在53周後被自動清除。
(注:關於擴充套件統計資訊的更多資訊可見文章“理解優化器統計資訊”)
舉個例子,在前面的例子中,SQL計劃指令16334867421200019996被創建於customers表。這個SQL計劃指令被建立的原因是多個單列謂詞之間的相關性。 一個CUST_CITY, CUST_STATE_PROVINCE,和 COUNTRY_ID上的列群組就可以解決基數估算偏差。下一次收集customers表的統計資訊的時候,這個列群組就會被自動建立。
(圖17. 基於SQL計劃指令自動建立的列群組)
下次這個SQL語句被執行的時候,列群組統計資訊就會取代SQL計劃指令被使用。DBA_SQL_PLAN_DIRECTIVES中的state(狀態)列指明瞭一個SQL計劃指令在這個週期中目前處於哪個環節。
一旦單表的基數估算被解決,額外的SQL計劃指令可能被創建於同樣的語句來解決計劃中的其他問題,例如連線和分組的基數估算偏差。
(圖18. 隨著時間推移,為圖10中所見的SQL語句所建立的多個SQL計劃指令)
11、優化器統計資訊
12、新型的直方圖
13、頂級頻度直方圖
以PRODUCT_SALES表為例,這個表含有一個聖誕飾物公司的銷售資料。表中有 1.78M 行,共有632個不同的TIME_ID。但是PRODUCT_SALES資料的主體含有少於254個不同的值,因為每年的聖誕飾物主要都在12月銷售。為了讓優化器知道列中的資料發生傾斜,有必要在TIME_ID列上建立一個直方圖。在這個情況下,一個含有254個桶的頂級頻度直方圖被建立。
(圖19. PRODUCT_SALES表中TIME_ID列資料的分佈情況,以及之上所建立的頂級頻度直方圖)
14、混合直方圖
混合直方圖類似於傳統的等高直方圖,因為它只在列中不同值的個數大於254的時候才會被建立。可是,相似性也僅限於此。在混合直方圖中,沒有任何一個值會出現在多個桶的端點,這就允許直方圖包含更多的端點值,實際上也就是比等高直方圖具有更多的桶數。那麼,混合直方圖是如何標識頻繁值的?每個端點的頻度被記錄下來(在一個新的名為endpoint_repeat_count的列中),這樣就為每個端點值提供了更精確的指示。
以CUSTOMERS表的CUST_CITY_ID列為例。CUSTOMERS表中有55,500行資料,CUST_CITY_ID列有620個不同的值。在這種情況下頻度直方圖和頂級頻度直方圖都不合適。在Oracle 11g資料庫中,一個等高直方圖將會被建立在這個列上。這個等高直方圖有213個桶但是隻代表了42個頻繁值(出現在2個或更多的桶的端點的值)。CUST_CITY_ID列中實際的頻繁值個數是54(即,出現頻度大於總行數/桶數=55500/254的那些值有54個)。
在Oracle 12c資料庫中,一個混合直方圖會被建立。混合直方圖有254個桶,並且代表了所有54個頻繁值。實際上混合直方圖將63個值當作頻繁值。這意味著在Oracle 11g資料庫中被當作近似頻繁值(只在一個桶中作為端點值)現在被處理為頻繁值,並且將會有更精確的基數估算。圖20顯示了一個例子,在Oracle 11g資料庫中的一個近似頻繁值(52114)如何在Oracle 12c資料庫中得到更佳的基數估算。
在 CUST_CITY_ID=52114的資料總共有227行:
(圖 20. 混合直方圖使得那些Oracle 11g資料庫中被當作近似頻繁值的值得到更精確的基數估算)
15、統計資訊線上收集
(圖21. 統計資訊線上收集為新建立的SALES2表同時提供了表統計和列統計資訊)
統計資訊線上收集並不包括收集直方圖或者索引統計,因為這些型別的統計資訊需要額外的掃描,這可能會對資料載入的效能造成很大的影響。為了收集必要的直方圖和索引統計,而無需重新收集基礎列統計資訊,請使用DBMS_STATS.GATHER_TABLE_STATS過程並將options引數設定為新的GATHER AUTO選項。
(圖22. 將 options 設為 GATHER AUTO 在SALES2表上建立了直方圖而無需收集基礎統計資訊)
備註列中的“HISTOGRAM_ONLY”指明直方圖在沒有重新收集基礎列統計的情況下被收集。GATHER AUTO選項僅在統計資訊的線上收集發生之後被推薦使用。
有兩種方法可以確定統計資訊的線上收集是否發生:檢查執行計劃,看看新的資料來源OPTIMIZER STATISTICS GATHERING是否在計劃中出現,或者檢視USER_TAB_COL_STATISTICS表的新的NOTES列,看看是否有狀態值STATS_ON_LOAD。
(圖23. 統計資訊線上收集操作的執行計劃)
根據設計,統計資訊線上收集對直接路徑操作的效能影響要最小化,因此它只能發生於空物件的資料載入。在向一張現有的表的新的分割槽中載入資料的時候,為了確保統計資訊線上收集能夠發生,請使用擴充套件的語法來顯式指定分割槽。在這種情況下,分割槽級別的統計資訊會被建立,但是全域性(表級別)統計資訊不會被修改。如果增量統計資訊在分割槽表上被開啟,一份綱要也會作為資料載入的一部分被建立。(譯註: 綱要(synopsis)是在表分割槽級別收集的輔助統計資訊,包含這個分割槽的某個列的不同值(NDV)的清單,根據這個資訊可以推算出全表的不同值)
(圖24. 在往現有分割槽表插入操作時發生了統計資訊線上收集)
注意,在語句級別指定提示NO_GATHER_OPTIMIZER_STATISTICS可以關閉統計資訊線上收集。