Oracle 繫結變數窺探

dawn009發表於2014-08-01
    Bind Peeking是Oracle 9i中引入的新特性,一直持續到Oracle 10g R2。它的作用就是在SQL語句硬分析的時候,檢視一下當前SQL謂詞的值
,以便生成最佳的執行計劃。而在oracle 9i之前的版本中,Oracle 只根據統計資訊來做出執行計劃。

一、繫結變數窺探 
    使用SQL首次執行時的值來生成執行計劃。後續再次執行該SQL語句則使用首次執行計劃來執行。
    影響的版本:Oracle 9i, Oracle 10g
    對於繫結變數列中的特殊值或非均勻分佈列上的繫結變數會造成非高效的執行計劃被選擇並執行。
    
        要注意的是,Bind Peeking只發生在硬分析的時候,即SQL被第一次執行的時候,之後的變數將不會在做peeking。我們可以看出,Bind 
    peeking並不能最終解決不同謂詞導致選擇不同執行計劃的問題,它只能讓SQL第一次執行的時候,執行計劃選擇更加準確,並不能幫助OLAP
    系統解決繫結變數導致執行計劃選擇錯誤的問題。這也是OLAP不應該使用繫結變數的一個原因。

        更確切地說,繫結變數窺探是在SQL解析的物理階段,查詢最佳化器將會窺探繫結變數的值並將其作為字面量來使用。即ORACLE首次解析
    SQL時會將變數的真實值代入產生執行計劃,後續對所有使用該繫結變數SQL語句都採用首次生存的執行計劃。如此這般?那效能究竟如何?
    結果是並非最佳的執行計劃的使用。此問題在Oracle 11g中得以解決。  
        請參考:Oracle自適應共享遊標

二、示例繫結變數窺探
    1、建立演示環境       

  1. SQL> select * from v$version where rownum<2;    --&gt檢視當前資料庫版本                                           
  2.                                                                                                                 
  3. BANNER                                                                                                          
  4. ----------------------------------------------------------------                                                
  5. Oracle Database 10g Release 10.2.0.3.0 - 64bit Production                                                       
  6.                                                                                                                 
  7. SQL> create table t(id,owner,object_id) as       --&gt建立測試表t                                                 
  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);  --&gt為表t新增主鍵                                       
  11.                                                                                                                 
  12. SQL> begin                                               --&gt收集統計資訊,此處未生成直方圖資訊                   
  13.   2  dbms_stats.gather_table_stats(                                                                             
  14.   3  ownname=>'SCOTT',                                                                                          
  15.   4  tabname=>'T',                                                                                              
  16.   5  estimate_percent=>100,                                                                                     
  17.   6  method_opt=>'for all columns size 1');                                                                     
  18.   7  end;                                                                                                       
  19.   8  /                                                                                                          
  20.                                                                                                                 
  21. PL/SQL procedure successfully completed.                                                                        
  22.                                                                                                                 
  23. SQL> select count(id),count(distinct id),min(id),max(id) from t;  --&gt檢視值的分佈情況                           
  24.                                                                                                                 
  25.  COUNT(ID) COUNT(DISTINCTID)    MIN(ID)    MAX(ID)                                                              
  26. ---------- ----------------- ---------- ----------                                                              
  27.       1000              1000          1       1000                                                              

    2、未使用繫結變數情形下SQL語句的執行計劃       

  1. SQL> select sum(object_id) from t where id<900;     --&gt釋出SQL 查詢語句                                                
  2.                                                                                                                        
  3. SUM(OBJECT_ID)                                                                                                         
  4. --------------                                                                                                         
  5.         446549                                                                                                         
  6.                                                                                                                        
  7. SQL> select * from table(dbms_xplan.display_cursor()); --&gt由其執行計劃可知,當前的SQL語句使用了全表掃描                
  8. /**************************************************/                                                                   
  9. /* Author: Robinson Cheng                         */                                                                   
  10. /* Blog:   http://blog.csdn.net/robinson_0612     */                                                                   
  11. /* MSN:    robinson_0612@hotmail.com              */                                                                   
  12. /* QQ:     645746311                              */                                                                   
  13. /**************************************************/                                                                   
  14.                                                                                                                                
  15. PLAN_TABLE_OUTPUT                                                                                                      
  16. ---------------------------------------------------------------------------                                            
  17. SQL_ID  bz6h6fdsxgjka, child number 0                                                                                  
  18. -------------------------------------                                                                                  
  19. select sum(object_id) from t where id<900                                                                              
  20.                                                                                                                        
  21. Plan hash value: 2966233522                                                                                            
  22.                                                                                                                        
  23. ---------------------------------------------------------------------------                                            
  24. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  25. ---------------------------------------------------------------------------                                            
  26. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  27. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  28. |*  2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |                                            
  29. ---------------------------------------------------------------------------                                            
  30.                                                                                                                        
  31. Predicate Information (identified by operation id):                                                                    
  32. ---------------------------------------------------                                                                    
  33.                                                                                                                        
  34.    2 - filter("ID"<900)                                                                                                
  35.                                                                                                                        
  36. SQL> select sum(object_id) from t where id<10;   --&gt釋出另一條SQL 查詢語句                                             
  37.                                                                                                                        
  38. SQL> select * from table(dbms_xplan.display_cursor()); --&gt此時的查詢生成的執行計劃走索引範圍掃描                       
  39.                                                        --&gt由於字面量不同,因此兩條SQL語句生成了不同的SQL_ID與執行計劃  
  40. PLAN_TABLE_OUTPUT                                                                                                      
  41. --------------------------------------------------------------------------                                             
  42. SQL_ID  6y2280pyvacfq, child number 0                                                                                  
  43. -------------------------------------                                                                                  
  44. select sum(object_id) from t where id<10                                                                               
  45.                                                                                                                        
  46. Plan hash value: 4270555908                                                                                            
  47.                                                                                                                        
  48. -------------------------------------------------------------------------------------                                  
  49. | Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                  
  50. -------------------------------------------------------------------------------------                                  
  51. |   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |                                  
  52. |   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |                                  
  53. |   2 |   TABLE ACCESS BY INDEX ROWID| T    |     9 |    72 |     3   (0)| 00:00:01 |                                  
  54. |*  3 |    INDEX RANGE SCAN          | T_PK |     9 |       |     2   (0)| 00:00:01 |                                  
  55. -------------------------------------------------------------------------------------                                  
  56.                                                                                                                        
  57. Predicate Information (identified by operation id):                                                                    
  58. ---------------------------------------------------                                                                    
  59.                                                                                                                        
  60.    3 - access("ID"<10)                                                                                                 

    3、使用繫結變數情形下的執行計劃             

  1. SQL> variable v_id number;   --&gt定義繫結變數                                                                           
  2. SQL> exec :v_id:=900;        --&gt給繫結變數賦值                                                                         
  3.                                                                                                                        
  4. PL/SQL procedure successfully completed.                                                                               
  5.                                                                                                                        
  6. SQL> select sum(object_id) from t where id<:v_id>
  7.                                                                                                                        
  8. SUM(OBJECT_ID)                                                                                                         
  9. --------------                                                                                                         
  10.         446549                                                                                                         
  11.                                                                                                                        
  12. SQL> select * from table(dbms_xplan.display_cursor());   --&gt此時上一條SQL語句走了全表掃描,其SQL_ID 為7qcp6urqh7d2j    
  13.                                                                                                                        
  14. PLAN_TABLE_OUTPUT                                                                                                      
  15. ------------------------------------------------------------------------------                                         
  16. SQL_ID  7qcp6urqh7d2j, child number 0                                                                                  
  17. -------------------------------------                                                                                  
  18. select sum(object_id) from t where id<:v_id>
  19.                                                                                                                        
  20. Plan hash value: 2966233522                                                                                            
  21.                                                                                                                        
  22. ---------------------------------------------------------------------------                                            
  23. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  24. ---------------------------------------------------------------------------                                            
  25. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  26. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  27. |*  2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |                                            
  28. ---------------------------------------------------------------------------                                            
  29.                                                                                                                        
  30. Predicate Information (identified by operation id):                                                                    
  31. ---------------------------------------------------                                                                    
  32.                                                                                                                        
  33.    2 - filter("ID"<:v_id>--&gt謂詞資訊表明此時使用了繫結變數                                                         
  34.                                                                                                                        
  35. SQL> exec :v_id:=10;         --&gt對繫結變數重新賦值                                                                     
  36.                                                                                                                        
  37. PL/SQL procedure successfully completed.                                                                               
  38.                                                                                                                        
  39. SQL> select sum(object_id) from t where id<:v_id>--&gt再次執行SQL語句                                                 
  40.                                                                                                                        
  41. SUM(OBJECT_ID)                                                                                                         
  42. --------------                                                                                                         
  43.            254                                                                                                         
  44.                                                                                                                        
  45. SQL> select * from table(dbms_xplan.display_cursor());  --&gt此時執行計劃中依然選擇的是全表掃描                          
  46.                                                         --&gt其SQL_ID同上一次執行的SQL語句相同,即實現了完全共享         
  47. PLAN_TABLE_OUTPUT                                       --&gt對於未使用繫結變數時id<10的情形則為走索引範圍掃描           
  48. -----------------------------------------------         --&gt由此可知,並非最佳的執行計劃被執行                          
  49. SQL_ID  7qcp6urqh7d2j, child number 0                                                                                  
  50. -------------------------------------                                                                                  
  51. select sum(object_id) from t where id<:v_id>
  52.                                                                                                                        
  53. Plan hash value: 2966233522                                                                                            
  54.                                                                                                                        
  55. ---------------------------------------------------------------------------                                            
  56. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                            
  57. ---------------------------------------------------------------------------                                            
  58. |   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |                                            
  59. |   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |                                            
  60. |*  2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |                                            
  61. ---------------------------------------------------------------------------                                            
  62.                                                                                                                        
  63. Predicate Information (identified by operation id):                                                                    
  64. ---------------------------------------------------                                                                    
  65.                                                                                                                        
  66.    2 - filter("ID"<:v_id>
  67.                                                                                                                        
  68. SQL> alter system flush shared_pool;    --&gt清空共享池,此時共享的父遊標與子游標全部釋放                                
  69.                                                                                                                            
  70. SQL> print v_id;                                                                                                       
  71.                                                                                                                        
  72.       V_ID                                                                                                             
  73. ----------                                                                                                             
  74.         10                                                                                                             
  75.                                                                                                                        
  76. SQL> select round(avg(object_id)) from t where id<:v_id>--&gt使用id<10來執行SQL語句                                   
  77.                                                                                                                        
  78. ROUND(AVG(OBJECT_ID))                                                                                                  
  79. ---------------------                                                                                                  
  80.                    28                                                                                                  
  81.                                                                                                                        
  82. SQL> select * from table(dbms_xplan.display_cursor());    --&gt此時該SQL語句使用了最佳的執行計劃,即走索引範圍掃描       
  83.                                                                                                                        
  84. PLAN_TABLE_OUTPUT                                                                                                      
  85. ---------------------------------------------------------------------------------------                                
  86. SQL_ID  0bx53mgt4qqnt, child number 0                                                                                  
  87. -------------------------------------                                                                                  
  88. select round(avg(object_id)) from t where id<:v_id>
  89.                                                                                                                        
  90. Plan hash value: 4270555908                                                                                            
  91.                                                                                                                        
  92. -------------------------------------------------------------------------------------                                  
  93. | Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                  
  94. -------------------------------------------------------------------------------------                                  
  95. |   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |                                  
  96. |   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |                                  
  97. |   2 |   TABLE ACCESS BY INDEX ROWID| T    |     9 |    72 |     3   (0)| 00:00:01 |                                  
  98. |*  3 |    INDEX RANGE SCAN          | T_PK |     9 |       |     2   (0)| 00:00:01 |                                  
  99. -------------------------------------------------------------------------------------                                  
  100.                                                                                                                        
  101. Predicate Information (identified by operation id):                                                                    
  102. ---------------------------------------------------                                                                    
  103.                                                                                                                        
  104.    3 - access("ID"<:v_id>
  105.                                                                                                                        
  106. SQL> exec :v_id:=900;                   --&gt為變數賦新值                                                                
  107.                                                                                                                        
  108. PL/SQL procedure successfully completed.                                                                               
  109.                                                                                                                        
  110. SQL> select round(avg(object_id)) from t where id<:v_id>
  111.                                                                                                                        
  112. ROUND(AVG(OBJECT_ID))                                                                                                  
  113. ---------------------                                                                                                  
  114.                   497                                                                                                  
  115.                                                                                                                        
  116. SQL> select * from table(dbms_xplan.display_cursor()); --&gt此次執行的SQL語句本該使用全表掃描,而此時選擇了索引範圍掃描  
  117.                                                                                                                        
  118. PLAN_TABLE_OUTPUT                                                                                                      
  119. --------------------------------------------------------------------------------------                                 
  120. SQL_ID  0bx53mgt4qqnt, child number 0                                                                                  
  121. -------------------------------------                                                                                  
  122. select round(avg(object_id)) from t where id<:v_id>
  123.                                                                                                                        
  124. Plan hash value: 4270555908                                                                                            
  125.                                                                                                                        
  126. -------------------------------------------------------------------------------------                                  
  127. | Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |                                  
  128. -------------------------------------------------------------------------------------                                  
  129. |   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |                                  
  130. |   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |                                  
  131. |   2 |   TABLE ACCESS BY INDEX ROWID| T    |     9 |    72 |     3   (0)| 00:00:01 |                                  
  132. |*  3 |    INDEX RANGE SCAN          | T_PK |     9 |       |     2   (0)| 00:00:01 |                                  
  133. -------------------------------------------------------------------------------------                                  
  134.                                                                                                                        
  135. Predicate Information (identified by operation id):                                                                    
  136. ---------------------------------------------------                                                                    
  137.                                                                                                                        
  138.    3 - access("ID"<:v_id>
  139.                                                                                                                        
  140. SQL> drop table t;                                                                                                     

三、總結
    從上面的演示可以,由於繫結變數窺探特性,對於後續生成的執行計劃,不僅套用了首次生成的執行計劃,而且執行計劃中的Row,Bytes,
Cost(%CPU)等都與首次生存執行計劃得值相同。由此可知,儘管可以使用繫結變數解決OLTP系統中大量重複SQL的反覆解析的問題。但繫結變數
可能會導致SQL語句選擇非最佳的執行計劃。尤其是對於存在資料傾斜的列,且生成了直方圖更不宜於使用繫結變數。在Oracle 11g 中,自適
應特性從一定程度解決了繫結變數窺探所導致的問題。

四、延伸參考
    Oracle自適應共享遊標
    繫結變數及其優缺點 

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

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

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

相關文章