Oracle自適應共享遊標

dawn009發表於2014-08-01
    自適應遊標共享Adaptive Cursor Sharing或擴充套件的遊標共享(Extended Cursor Sharing)是Oracle 11g的新特性之一,主要用於解決以前版
本中由於繫結變數窺探導致SQL語句無法獲得最佳執行計劃的缺陷,即能夠對效率低下的遊標(子游標)進行自動識別而選擇最佳的執行計劃。本
文詳細描述了自適應遊標共享並給出示例。
    有關繫結變數窺探請參考:Oracle 繫結變數窺探

一、示例自適應遊標共享
    1、建立演示環境       

  1. SQL> select * from v$version where rownum<2;                                                    
  2.                                                                                                 
  3. BANNER                                                                                          
  4. --------------------------------------------------------------------------------                
  5. Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production                          
  6.                                                                                                     
  7. SQL> create table t(id,owner,object_id) as                                                      
  8.   2  select rownum,owner,object_id from all_objects where rownum<=1000;                         
  9.                                                                                                 
  10. SQL> alter table t add constraint t_pk primary key(id);                                         
  11.                                                                                                 
  12. SQL> exec dbms_stats.gather_table_stats('SCOTT','T',cascade=>true);                             
  13.                                                                                                 
  14. SQL> select count(id),count(distinct id),min(id),max(id) from t;                                
  15.                                                                                                 
  16.  COUNT(ID) COUNT(DISTINCTID)    MIN(ID)    MAX(ID)                                              
  17. ---------- ----------------- ---------- ----------                                              
  18.       1000              1000          1       1000                                              

    2、使用繫結變數執行SQL語句並獲得首次執行情況        

  1. SQL> var v_id number;                                                                                              
  2. SQL> exec :v_id:=9;                                                                                                
  3. SQL> set linesize 180                                                                                              
  4. SQL> select sum(object_id) from t where id<:v_id>
  5.                                                                                                                    
  6. SUM(OBJECT_ID)                                                                                                     
  7. --------------                                                                                                     
  8.           2078                                                                                                     
  9. SQL> select * from table(dbms_xplan.display_cursor(null,null,'typical -predicate'));                               
  10. SQL_ID  7qcp6urqh7d2j, child number 0                                                                              
  11. -------------------------------------                                                                              
  12. select sum(object_id) from t where id<:v_id>--&gt變數值為9時,使用了正確的執行計劃,且預估的行數也準確    
  13.                                                                                                                    
  14. Plan hash value: 4270555908                                                                                        
  15.                                                                                                                    
  16. -------------------------------------------------------------------------------------                              
  17. | Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |                              
  18. -------------------------------------------------------------------------------------                              
  19. |   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |                              
  20. |   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |                              
  21. |   2 |   TABLE ACCESS BY INDEX ROWID| T    |     8 |    64 |     3   (0)| 00:00:01 |                              
  22. |   3 |    INDEX RANGE SCAN          | T_PK |     8 |       |     2   (0)| 00:00:01 |                              
  23. -------------------------------------------------------------------------------------                              
  24.                                                                                                                    
  25. SQL> col SQL_TEXT format a45    --&gt下面的語句獲得自適應遊標共享的3個欄位值                                         
  26. SQL> select sql_id,sql_text,child_number,executions,is_bind_sensitive,is_bind_aware,is_shareable                   
  27.   2  from v$sql where sql_text like '%select sum(object_id) from t where%' and sql_text not like '%from v$sql%';   
  28.                                                                                                                    
  29. SQL_ID        SQL_TEXT                                      CHILD_NUMBER EXECUTIONS I I I                          
  30. ------------- --------------------------------------------- ------------ ---------- - - -                          
  31. 7qcp6urqh7d2j select sum(object_id) from t where id<:v_id>

    3、自適應遊標共享的外在體現
        自適應遊標共享主要透過三個欄位來得以體現,即is_bind_sensitive,is_bind_aware,is_shareable。(注:此三個欄位僅在Oracle 11g
        中存在)。透過上面從v$sql(v$sqlarea中不存在is_shareable)的查詢可知,三個欄位分別被賦予了不同的值,代表了不同的含義。
      
      is_bind_sensitive(繫結是否敏感)
          表示該子游標中是否使用了繫結變數要素,且採用bind peeking方法進行執行計劃生成。如果執行計劃依賴於窺探到的值,此處為Y,
          否則為N。
      
      is_bind_aware(繫結是否可知)
          表示該子游標是否使用了extended cursor sharing技術,是則為Y,否則為N,如為N,則該遊標將廢棄,不再可用。
      
      is_shareable(是否可共享)
          表示該子游標可否被下次軟解析是否可共享使用。可共享則為Y,否則為N,表示該子游標失去了共享價值,按LRU演算法淘汰。
  
      由於該SQL語句為首次執行,因此從v$sql查詢的結果中得知
          is_bind_sensitive 為Y值(首次執行,執行了bind peeking)
          is_bind_aware     為N值(首次執行,不被extended cursor sharing支援)
          is_shareable      為Y值(執行計劃可共享)

    4、重新賦值後觀察遊標共享情況       

  1. SQL> exec :v_id:=900;                                                                                                  
  2. SQL> select sum(object_id) from t where id<:v_id>
  3.                                                                                                                        
  4. SUM(OBJECT_ID)                                                                                                         
  5. --------------                                                                                                         
  6.        1826561                                                                                                         
  7.                                                                                                                        
  8. SQL> select * from table(dbms_xplan.display_cursor(null,null,'typical -predicate'));                                   
  9.                                                                                                                        
  10. SQL_ID  7qcp6urqh7d2j, child number 0                                                                                  
  11. -------------------------------------                                                                                  
  12. select sum(object_id) from t where id<:v_id>--&gt此次執行的變數值為900,執行計劃位上次變數為9的執行計劃                 
  13.                                              --&gt此時為非正確的執行計劃,等同於Oracle 9i,10g中的情形                    
  14. Plan hash value: 4270555908                                                                                            
  15.                                                                                                                        
  16. -------------------------------------------------------------------------------------                                  
  17. | Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                  
  18. -------------------------------------------------------------------------------------                                  
  19. |   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |                                  
  20. |   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |                                  
  21. |   2 |   TABLE ACCESS BY INDEX ROWID| T    |     8 |    64 |     3   (0)| 00:00:01 |                                  
  22. |   3 |    INDEX RANGE SCAN          | T_PK |     8 |       |     2   (0)| 00:00:01 |                                  
  23. -------------------------------------------------------------------------------------                                  
  24.                                                                                                                        
  25. --&gt自適應遊標共享的3個欄位值並未發生任何變化                                                                           
  26. SQL> select sql_id,sql_text,child_number,executions,is_bind_sensitive,is_bind_aware,is_shareable                       
  27.   2  from v$sql where sql_text like '%select sum(object_id) from t where%' and sql_text not like '%from v$sql%';       
  28.                                                                                                                        
  29. SQL_ID        SQL_TEXT                                      CHILD_NUMBER EXECUTIONS I I I                              
  30. ------------- --------------------------------------------- ------------ ---------- - - -                              
  31. 7qcp6urqh7d2j select sum(object_id) from t where id<:v_id>
  32.                                                                                                                        
  33. SQL> select sum(object_id) from t where id<:v_id>--&gt再次執行變數為900值的SQL語句                                    
  34.                                                                                                                        
  35. SUM(OBJECT_ID)                                                                                                         
  36. --------------                                                                                                         
  37.        1826561                                                                                                         
  38.                                                                                                                        
  39. SQL> select * from table(dbms_xplan.display_cursor(null,null,'typical -predicate'));                                   
  40.                                                                                                                        
  41. SQL_ID  7qcp6urqh7d2j, child number 1                                                                                  
  42. -------------------------------------                                                                                  
  43. select sum(object_id) from t where id<:v_id>--&gt此時執行計劃較上一次發生了變化,使用了全表掃描,Rows接近於實際值      
  44.                                                --&gt自適應遊標共享特性得以體現                                           
  45. Plan hash value: 2966233522                                                                                            
  46.                                                                                                                        
  47. ---------------------------------------------------------------------------                                            
  48. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  49. ---------------------------------------------------------------------------                                            
  50. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  51. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  52. |   2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |                                            
  53. ---------------------------------------------------------------------------                                            
  54.                                                                                                                        
  55. --&gt自適應遊標共享特性的幾個值發生了變化,生成了新的子游標,其子游標號為1                                               
  56. SQL> select sql_id,sql_text,child_number,executions,is_bind_sensitive,is_bind_aware,is_shareable                       
  57.   2  from v$sql where sql_text like '%select sum(object_id) from t where%' and sql_text not like '%from v$sql%';       
  58.                                                                                                                        
  59. SQL_ID        SQL_TEXT                                      CHILD_NUMBER EXECUTIONS I I I                              
  60. ------------- --------------------------------------------- ------------ ---------- - - -                              
  61. 7qcp6urqh7d2j select sum(object_id) from t where id<:v_id>
  62. 7qcp6urqh7d2j select sum(object_id) from t where id<:v_id>
  63.                                                                                                                        
  64. SQL> exec :v_id:=800      --&gt為變數賦於不同的值                                                                        
  65.                                                                                                                        
  66. SQL> select sum(object_id) from t where id<:v_id>--&gt利用新的變數值執行SQL語句                                        
  67.                                                                                                                        
  68. SUM(OBJECT_ID)                                                                                                         
  69. --------------                                                                                                         
  70.        1548431                                                                                                         
  71.                                                                                                                        
  72. SQL> select sql_id,child_number,executions,is_bind_sensitive,is_bind_aware,is_shareable                                
  73.   2  from v$sql where sql_text like '%select sum(object_id) from t where%' and sql_text not like '%from v$sql%';       
  74.                                                                                                                        
  75. SQL_ID        CHILD_NUMBER EXECUTIONS I I I                                                                            
  76. ------------- ------------ ---------- - - -                                                                            
  77. 7qcp6urqh7d2j            0          2 Y N Y                                                                            
  78. 7qcp6urqh7d2j            1          1 Y Y N                                                                            
  79. 7qcp6urqh7d2j            2          1 Y Y Y    --&gt生成了新的子游標號為2                                                
  80.                                                                                                                        
  81. SQL> exec :v_id:=500;     --&gt為變數賦於新值                                                                            
  82.                                                                                                                        
  83. SQL> select sum(object_id) from t where id<:v_id>--&gt利用新的變數值執行SQL語句                                        
  84.                                                                                                                        
  85. SUM(OBJECT_ID)                                                                                                         
  86. --------------                                                                                                         
  87.         826694                                                                                                         
  88.                                                                                                                        
  89. /**************************************************/                                                                   
  90. /* Author: Robinson Cheng                         */                                                                   
  91. /* Blog:   http://blog.csdn.net/robinson_0612     */                                                                   
  92. /* MSN:    robinson_0612@hotmail.com              */                                                                   
  93. /* QQ:     645746311                              */                                                                   
  94. /**************************************************/                                                                   
  95.                                                                                                                        
  96. SQL> select sql_id,child_number,executions,is_bind_sensitive,is_bind_aware,is_shareable                                
  97.   2  from v$sql where sql_text like '%select sum(object_id) from t where%' and sql_text not like '%from v$sql%';       
  98.                                                                                                                        
  99. SQL_ID        CHILD_NUMBER EXECUTIONS I I I                                                                            
  100. ------------- ------------ ---------- - - -                                                                            
  101. 7qcp6urqh7d2j            0          2 Y N Y                                                                            
  102. 7qcp6urqh7d2j            1          1 Y Y N                                                                            
  103. 7qcp6urqh7d2j            2          1 Y Y N       --&gt注意看子游標1,2的is_shareable值為N,表示不可共享                  
  104. 7qcp6urqh7d2j            3          1 Y Y Y       --&gt生成了新的子游標號為3,                                           
  105.                                                                                                                        
  106. --&gt檢視最終該SQL語句的不同子游標的所有執行計劃                                                                         
  107. SQL> select * from table(dbms_xplan.display_cursor('7qcp6urqh7d2j',null,'typical -predicate'));                        
  108.                                                                                                                        
  109. PLAN_TABLE_OUTPUT                                                                                                      
  110. ------------------------------------------------------------------------------------------------------------------     
  111. SQL_ID  7qcp6urqh7d2j, child number 0                                                                                  
  112. -------------------------------------                                                                                  
  113. select sum(object_id) from t where id<:v_id>--&gt0號子游標為索引範圍掃描                                             
  114.                                                                                                                        
  115. Plan hash value: 4270555908                                                                                            
  116.                                                                                                                        
  117. -------------------------------------------------------------------------------------                                  
  118. | Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                  
  119. -------------------------------------------------------------------------------------                                  
  120. |   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |                                  
  121. |   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |                                  
  122. |   2 |   TABLE ACCESS BY INDEX ROWID| T    |     8 |    64 |     3   (0)| 00:00:01 |                                  
  123. |   3 |    INDEX RANGE SCAN          | T_PK |     8 |       |     2   (0)| 00:00:01 |                                  
  124. -------------------------------------------------------------------------------------                                  
  125.                                                                                                                        
  126. SQL_ID  7qcp6urqh7d2j, child number 1                                                                                  
  127. -------------------------------------                                                                                  
  128. select sum(object_id) from t where id<:v_id>--&gt1號子游標為全表掃描,其預估的行數接近實際影響行數的值為900            
  129.                                                                                                                        
  130. Plan hash value: 2966233522                                                                                            
  131.                                                                                                                        
  132. ---------------------------------------------------------------------------                                            
  133. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  134. ---------------------------------------------------------------------------                                            
  135. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  136. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  137. |   2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |                                            
  138. ---------------------------------------------------------------------------                                            
  139.                                                                                                                        
  140. SQL_ID  7qcp6urqh7d2j, child number 2                                                                                  
  141. -------------------------------------                                                                                  
  142. select sum(object_id) from t where id<:v_id>--&gt2號子游標為全表掃描,但其預估的行數接近實際影響行數的值為800          
  143.                                                                                                                        
  144. Plan hash value: 2966233522                                                                                            
  145.                                                                                                                        
  146. ---------------------------------------------------------------------------                                            
  147. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  148. ---------------------------------------------------------------------------                                            
  149. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  150. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  151. |   2 |   TABLE ACCESS FULL| T    |   800 |  6400 |     3   (0)| 00:00:01 |                                            
  152. ---------------------------------------------------------------------------                                            
  153.                                                                                                                        
  154. SQL_ID  7qcp6urqh7d2j, child number 3                                                                                  
  155. -------------------------------------                                                                                  
  156. select sum(object_id) from t where id<:v_id>--&gt3號子游標為全表掃描,但其預估的行數等於實際影響行數的值499             
  157.                                                                                                                        
  158. Plan hash value: 2966233522                                                                                            
  159.                                                                                                                        
  160. ---------------------------------------------------------------------------                                            
  161. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  162. ---------------------------------------------------------------------------                                            
  163. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  164. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  165. |   2 |   TABLE ACCESS FULL| T    |   499 |  3992 |     3   (0)| 00:00:01 |                                            
  166. ---------------------------------------------------------------------------                                            

二、自適應遊標共享的幾個相關檢視

 1、v$sql_cs_statistics
        用於監控自適應遊標共享的相關統計資訊.下面的查詢中列出了每個子游標的peeking情況,以及執行次數,預處理行數,BUFFER_GETS等       

  1. SQL> select child_number,bind_set_hash_value,peeked,executions,rows_processed,buffer_gets                        
  2.   2  from v$sql_cs_statistics where sql_id='7qcp6urqh7d2j'                                                       
  3.   3  order by 1;                                                                                                 
  4.                                                                                                                  
  5. CHILD_NUMBER BIND_SET_HASH_VALUE P EXECUTIONS ROWS_PROCESSED BUFFER_GETS                                         
  6. ------------ ------------------- - ---------- -------------- -----------                                         
  7.            0          1706589901 Y          1             17          69     --&gt17行,索引範圍掃描               
  8.            1          3116944019 Y          1            900           5     --&gt900行,全表掃描                  
  9.            2          1328865654 Y          1            800           5     --&gt800行,全表掃描                  
  10.            3          1624350242 Y          1            500           5     --&gt500行,全表掃描                  

    2、v$sql_cs_selectivity
        顯示每個子游標的遊標的選擇性範圍。下面的查詢中列出了謂詞,選擇性範圍,列上的選擇性的值       

  1. SQL> select child_number,predicate,range_id,low,high from v$sql_cs_selectivity         
  2.   2  where sql_id='7qcp6urqh7d2j' order by 1;                                          
  3.                                                                                        
  4. CHILD_NUMBER PREDICATE            RANGE_ID LOW        HIGH                             
  5. ------------ ------------------ ---------- ---------- ----------                       
  6.            1 
  7.            2 
  8.            3 

    3、v$sql_cs_histogram
        用於決定一個查詢是否允許自適應遊標共享,以直方圖形式儲存       

  1. SQL> select CHILD_NUMBER,BUCKET_ID,COUNT from v$sql_cs_histogram where SQL_ID='7qcp6urqh7d2j'     
  2.   2  order by 1;                                                                                  
  3.                                                                                                   
  4. CHILD_NUMBER  BUCKET_ID      COUNT                                                                
  5. ------------ ---------- ----------                                                                
  6.            0          1          1                                                                
  7.            0          0          1                                                                
  8.            0          2          0                                                                
  9.            1          1          0                                                                
  10.            1          0          1                                                                
  11.            1          2          0                                                                
  12.            2          1          0                                                                
  13.            2          0          1                                                                
  14.            2          2          0                                                                
  15.            3          1          0                                                                
  16.            3          0          1                                                                
  17.            3          2          0                                                                

三、總結
    1、自適應遊標共享在SQL語句首次執行時(使用繫結變數),進行窺探,並記錄窺探結果,如果後續有相同的的SQL語句執行,則對窺探結果
       進行比較以判斷是否需要生成新的執行計劃。此即為繫結變數是否敏感。
    2、繫結變數的可知性用於判斷當前的遊標是否為可擴充套件性遊標共享,當不可知時,則遊標被廢棄。
    3、自適應遊標共享的實質是在Oracle 10g以前的基礎上實現了多次繫結變數窺探,增加了獲取最佳執行計劃選擇的機率。
    4、儘管使用自適應遊標共享特性,但並不能保證每次執行SQL語句一定按最佳計劃執行,本次演示中SQL語句的第二次執行並非最佳執行計劃。
    5、自適應遊標共享也不能保證兩次執行相同SQL語句一定按相同的執行計劃執行,因為自適應遊標共享會不斷嘗試peeking。
               
四、延伸參考
    Oracle 繫結變數窺探
    Oracle自適應共享遊標
    繫結變數及其優缺點 

    父遊標、子游標及共享遊標 
    dbms_xplan之display_cursor函式的使用 
    dbms_xplan之display函式的使用 
    執行計劃中各欄位各模組描述

--&gt>轉載於:http://blog.csdn.net/leshami/article/details/6923670

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29119536/viewspace-1243966/,如需轉載,請註明出處,否則將追究法律責任。

相關文章