1. 程式人生 > >SQL和PL/SQL的效能優化之二--執行計劃管理

SQL和PL/SQL的效能優化之二--執行計劃管理

1、提示--它們僅是建議,優化器可以選擇忽略他們。事實上,優化器將盡可能地遵從優化提示,哪怕會導致空難性的效能影響。一般來說,只有當你用盡非直接方法(收集統計資訊,建立柱狀圖及設定配置引數等)之後,才可以考慮使用提示。

    下面是一些更常見的提示:

     ALL_ROWS 使用ALL_ROWS優化器目標

     AND_EQUALS(表名... 索引名 索引名 ···) 合併指定索引來提取指定的表的記錄,與下一個類似,但是不使用企業版才支援的位置轉換策略。

     INDEX_COMBINE(表名,索引名 索引名···) 與上面的類似,但是使用只有在企業版中才有的位置轉換策略

     APPEND   使用直接模式插入

     CACHE(表名)  當執行全表掃描操作時,促進表在ORACLE共享記憶體中的快取(NOCACHE反效)

     FACT(表名)  考慮使用指定的表作為星型模式的事實表

     FIRST_ROWS(N)  使用FIRST_ROWS優化器目標

     FULL(表名)

     HASH(表名)  對指定的表使用基於雜湊聚簇的訪問方式(顯然,只有與表是雜湊聚簇表時才有效)

     INDEX(表名[索引名]) 使用指定表上的指定索引。如果沒指定索引,則使用表上帶來最低開銷的那個索引

     INDEX_SS(表名 索此名) 使用索引“跳躍掃描”訪問路徑

     LEADING(表名···) 指定表作為聯結順序中驅動表,並指定順序進行連線

     PARALLEL(表名並行度) NOPARALLED

     ORDERED  使用FROM子句中表出現的順序作為聯結的順序,它將覆寫普通的基於成本計算得出來的聯結順序

     USE_HASH(表名)  雜湊聯結技術

     USE_MERGE(表名) 排序合併方法

     USE_NL(表名) 巢狀迴圈方法

 

2、儲存提綱:是在特定的時間點為特定的SQL語句記錄執行計劃的方法。然後你可以啟用儲存提綱以保證即使統計資訊在未來發生改變,特定的執行計劃依然會被使用。

     儲存提綱將被SQL計劃基線取代,但10G,11G標準版完全支援儲存提綱

     建立儲存提綱:

    Create outline customer_yob_qry for category outlines2 on

     select max(cust_income_level)

       from customers c

     where cust_year_of_birth >1985;

     每個儲存提綱都屬於一個特定的類目;上面的類目OUTLINES2,可以在會話級或系統級使用引數USE_STORED_OUTLINES來啟用。

     ALTER SESSION SET USE_STORED_OUTLINES=OUTLINES2;

     侵入儲存提綱:

     不能編輯SQL語句的情況下,強制SQL採用另一個不同的計劃。

          A>首先我們對未改變的SQL語句建立一個儲存提綱;

               Create outline customer_yob_otln for category outlines2 on

                select min(cust_income_level)

                  from customers c

               where cust_year_of_birth >1985;

          B>我們由公共儲存提綱建立一個私有儲存提綱

              Create Private outline original_oln from cust_yob_otln;

          C>現在我們建立一個擁有相同SQL語句但包含任何我們想指定的提示;

               Create private outline hinted_oln on

                  select /*+ index(c)*/ min(cust_income_level)

                    from customers c

                  where cust_year_of_birth>1985;

             查詢全域性臨時表ol$hints(它擁有私有儲存提綱的定義),可以看到應用於每個儲存提綱的提示,注意到original_oln有一個FULL提示,而hinted_oln有一個index提示。

             select on_name,hint_text from ol$hints;

           D>我們現在想做的是將HINTED_OLN中的提示覆制到ORIGINAL_OLN中。ol$hints表包含提示的內容,而它的父表,ol$包含提示的數量,它也必須被更新。

           下面的SQL語句交換儲存提綱:

            update ol$hints

                set  ol_name = case ol_name

                                               when 'HINTED_OLN'

                                                    then 'ORIGINAL_OLN'

                                                when 'ORIGINAL_OLN'

                                                    then 'HINTED_OLN'

                                                 else ol_name

                                             end

               where ol_name in('HINTED_OLN','ORIGINAL_OLN');

            update ol$ ol2

                 set hintcount=(select hintcount from ol$ ol2

                                         where ol2.ol_name in('HINTED_OLN','ORIGINAL_OLN')

                                             and ol2.ol_name != ol1.ol_name)

             where ol1.ol_name in('HINTED_OLN','ORIGINAL_OLN');

     現在,啟用私有儲存提綱,可以看到原始SQL語句成功強制使用了索引

     ALTER SESSION SET USE_PRIVATE_OUTLINES=TRUE;

     E>最後,我們要做的事就是把私有儲存提綱複製回原有的公有儲存提綱裡。

          Create or replace outline cust_yob_otln from

             private original_oln for category outlines2;

        現在,如果激活了儲存提綱類目OUTLINES2,SQL語句將會使用索引,就如其中包含了索引提示一樣。

3、SQL概要--為增加優化器的靈活性,當環境變化時,為新的SQL建立更優執行計劃的能力,SQL概要及相關的SQL調優顧問是10G引入的,需ORACLE調優包授權許可。

     SQL概要是一個由SQL調優任務建立的與該SQL相關的特定統計資訊的集合,它可以在隨後被SQL調優顧問用來決定一個最優的計劃,調優顧問可理解為一個離線優化器(offline optimizer)

4、SQL基線---為補充SQL概要並最終替代儲存提綱,11G中引入了SQL基線(靈活性與穩定性的結合)

     只有在新的計劃被證實好於任何已存在的計劃時,它才允許計劃改變。

     4、1 建立基線

     DECLARE

      V_SQL_ID v$sql.sql_id%type;

      V_PLAN_COUNT NUMBER;

      BEGIN

         SELECT SQL_ID INTO V_SQL_ID FROM V$SQL

          WHERE SQL_TEXT LIKE 'SELECT /*GHBASELINES1*/%';

        V_PLAN_COUNT := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(SQL_ID => V_SQL_ID);

         DBMS_OUTPUT.PUT_LINE(V_PLAN_COUNT||' PLANS  LOADED');

      END;

    表dba_sql_plan_baselines可查基線狀態,ACCEPTED列為YES表示這個基線被啟用。

     查基線對應的計劃

    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(:V_SQL_HANDEL,NULL,'BASIC'));

     進化基線

      當發現新的執行計劃開銷低時,優化器就會建立新的基線。然而新的基線在經過核實之前不會被接受。

      BEGIN

      :V_REPORT := dbms_spm.evolve_sql_plan_baseline

                                                   (sql_handle=>:v_sql_handle,

                                                    verify=>'YES',--只有當未接受的計劃可帶來顯著提升,才會被接受,如果設定為NO,則所有未接受的計劃都會被接受。

                                                    commit => 'YES');--控制實際真正接受,或僅僅報告計劃是否符合標準

      END;

      自動化和配置基線

      基線的使用主要由兩個資料庫引數控制

      OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES  這個引數控制基線的自動收集,預設設定為FALSE,當將基設為TRUE時,基線會在SQL第一次執行時被自動建立。這樣,就沒必要再使用DBMS_SPM包來手工建立基線了。

      OPTIMIZER_USE_SQL_PLAN_BASELINES 控制優化器對SQL基線的使用,預設值為TRUE,當為FALSE時,在優化器決定執行計劃時,就不會考慮基線。

      固化基線

       只需在前面的過程中做個小的修改:

      ...

     v_plan-count := dbms_spm.load_plans_from_cursor_cache(sql_id=>v_sql_id,fixed=>'YES');

      ...

     當有固化的基線存在時,即使有計劃發生變化,優化器也不會為這個SQL語句增加新的基線,一定是優化使用固化的基線。