oracle中綁定變量測試

從一個簡單的示例入手:java

建立測試表sql

create table t1 as select * from dba_objects;數據庫

使用一段java 代碼作測試。oracle

package dbtest;
import java.sql.*;
public class Dbtest {
   public static final String drive = "oracle.jdbc.driver.OracleDriver";
   public static final String url = "jdbc:oracle:thin:@//192.168.196.200:1521/orcl2pdb";
   public static final String DBUSER="wxc";
   public static final String password="wxc";
   public static void main(String[] args) throws Exception{
       // TODO Auto-generated method stub      
           Connection conn = null;//表示數據庫鏈接
           Statement stmt= null;//表示數據庫的更新
           ResultSet result = null;//查詢數據庫    
           Class.forName(drive);//使用class類來加載程序
           conn =DriverManager.getConnection(url,DBUSER,password); //鏈接數據庫
           //Statement接口要經過connection接口來進行實例化操做
           conn.setAutoCommit(false);
           stmt = conn.createStatement();
           //執行SQL語句來查詢數據庫
           stmt.execute("truncate table t9");
           long t1 = System.currentTimeMillis(); 
           for (int i = 0; i<=30000; i++ ){
           stmt.execute("insert into t9 values ("+i+")");
           }   
           conn.commit();    
           long t2 = System.currentTimeMillis(); 
           System.out.println("不使用邦定變量測試"+ (t2 - t1));
           stmt.execute("truncate table t9");
           long t3 = System.currentTimeMillis(); 
           PreparedStatement pstmt =conn.prepareStatement("insert into t9 values (?)"); 
           for (int i = 0 ; i<=30000; i++ ){
        	   pstmt.setInt(1, i);
           pstmt.executeUpdate(); } conn.commit(); long t4 = System.currentTimeMillis(); System.out.println("邦定變量測試"+ (t4 - t3)); conn.close();//關閉數據庫 } }

不使用邦定變量測試36805
邦定變量測試17080ide

結果能夠看出,使用綁定變量和不使用綁定 變量結果相差幾倍;性能

以下截圖中,使用綁定變量時,只生成一個遊標,如第一行所示,不使用綁定變量時,每次執行都會生成一個遊標,想一想不使用綁定變量時每條語句都要通過一次硬解析,對共享池的壓力是很大的。測試

使用綁定變量的很差之處,這裏舉例說明。url

將表t9 中owner列值改成100個爲public,其他都爲sys,模擬一個owner 數據嚴重傾斜的例子。spa

在sqlplus 下執行下例語句code

variable owner varchar2(100)
execute :owner := 'SYS';
select * from t1 where owner = :owner;
execute :owner := 'PUBLIC';
select * from t1 where owner = :owner;

檢查共享池 ,看到只生成了一個遊標

在共享池中的執行計劃以下

select * from table(dbms_xplan.display_cursor('d0g5mw5skptkq',0,'allstats advanced last'));

SQL_ID  d0g5mw5skptkq, child number 0
-------------------------------------
select * from t1 where owner = :owner
 
Plan hash value: 3617692013
 
---------------------------------------------------------------------------
| Id  | Operation         | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |        |       |   427 (100)|          |
|*  1 |  TABLE ACCESS FULL| T1   |  90944 |     9M|   427   (1)| 00:00:01 |
---------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / T1@SEL$1
Peeked Binds (identified by position):
--------------------------------------
 
   1 - :1 (VARCHAR2(30), CSID=178): 'SYS'
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("OWNER"=:OWNER)

上述執行計劃中,對於值sys,走全表掃描是比較合適的,可是對於public顯然不合適,綁定變量窺探的時候使用的是sys,黃色部分所示。使用綁定變量生成的執行計劃,若是不考慮實際的數據分佈狀況,會致使後續的執行盲目的沿用一個不合適的執行計劃。綁定變量的這種缺陷每每會致使一些嚴重的性能問題。

還好11gR2 中開始有自適應遊標共享,能夠糾正這種狀況。

 使用提示啓用自適應遊標共享

variable owner varchar2(100)
execute :owner := 'SYS';
select /*+ bind_aware */ * from t1 where owner = :owner;
execute :owner := 'PUBLIC';
select /*+ bind_aware */ * from t1 where owner = :owner;

查看共享池有兩個遊標

查看執行計劃

SQL_ID  8squu0a2shjfv, child number 0
-------------------------------------
select /*+ bind_aware  */ * from t1 where owner = :owner
 
Plan hash value: 3617692013
 
---------------------------------------------------------------------------
| Id  | Operation         | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |        |       |   427 (100)|          |
|*  1 |  TABLE ACCESS FULL| T1   |  90944 |     9M|   427   (1)| 00:00:01 |
---------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / T1@SEL$1
 
Peeked Binds (identified by position):
--------------------------------------
 
   1 - :1 (VARCHAR2(30), CSID=178): 'SYS'
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   1 - filter("OWNER"=:OWNER)
 
 
SQL_ID  8squu0a2shjfv, child number 1
-------------------------------------
select /*+ bind_aware  */ * from t1 where owner = :owner
 
Plan hash value: 2024642480
 
--------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name      | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |           |        |       |     3 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T1        |    100 | 11300 |     3   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | IDX_OWNER |    100 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - SEL$1 / T1@SEL$1
   2 - SEL$1 / T1@SEL$1
Peeked Binds (identified by position):
--------------------------------------
 
   1 - :1 (VARCHAR2(30), CSID=178): 'PUBLIC'
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("OWNER"=:OWNER)

能夠看到自適應遊標共享能夠解決因爲綁定變量形成執行計劃不許確這種狀況。

相關文章
相關標籤/搜索