AWR Execute to Parse引數解析

壹頁書發表於2014-11-04
最近最佳化單位的Oracle資料庫,
AWR部分內容如下

可以看到
Execute to Parse %和Execute to Parse % 指標很低.

其中
Execute to Parse %
表示SQL語句解析後被重複執行命中率 計算公式=100*(1-Parses/Executions)
如果該值偏小,說明分析(硬分析與軟分析 )的比例較大,快速分析較少,
根據實際情況,可以考慮調整session_cached_cursors引數
有些報告中這個值是負的,看上去很奇怪。事實上這表示一個問題,sql如果被age out的話就可能出現這種情況,也就是sql老化, 或 執行alter system flush shared_pool


Parse CPU to Parse Elapsd %
表示解析實際耗用時間/(解析實際耗用時間+等待資源的時間)
越高越好,在實際繁忙的系統中,該值可能因為等待資源而不會太高


這兩個指標還是牽扯到了軟軟解析的老問題
http://blog.csdn.net/stevendbaguo/article/details/17267161
http://blog.itpub.net/29254281/viewspace-1064007/

如果JAVA使用了引數化SQL,那麼每次執行SQL都是軟解析.
相對於硬解析,軟解析複用了執行計劃,
但是軟解析也會消耗資源(語法檢查,語義檢查,許可權檢查)

所以對於Oracle來說,軟軟解析才是最好的方式(我理解就是不解析...)
實現軟軟解析有兩種方式,一種是JAVA應用程式快取遊標,另一種是設定Oracle的session_cached_cursors引數(預設20)

假設JAVA程式獲取了一個遊標,使用之後沒有關閉,下次再次使用的時候,開啟遊標.oracle不會進行任何解析,而是直接使用執行計劃獲取資料。
即使關閉了該遊標,如果同一連線軟解析該SQL三次以上,Oracle也會將遊標快取在PGA。每個Session快取遊標的數量由session_cached_cursors決定。

從實驗看軟解析和軟軟解析

軟解析
每次執行之後,關閉遊標
  1. import java.sql.Connection;
  2. import java.sql.DriverManager;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.Future;

  10. public class Test implements Callable<Long> {
  11.     private static int COUNT = 100000;

  12.     public static void main(String[] args) throws Exception {
  13.         ExecutorService prepareThreadPool = Executors.newFixedThreadPool(4);
  14.         Future<Long> f1 = prepareThreadPool.submit(new Test());
  15.         Future<Long> f2 = prepareThreadPool.submit(new Test());
  16.         Future<Long> f3 = prepareThreadPool.submit(new Test());
  17.         Future<Long> f4 = prepareThreadPool.submit(new Test());
  18.         System.out.println("Wait");
  19.         Long totalTime = 0L;
  20.         totalTime = totalTime + f1.get();
  21.         totalTime = totalTime + f2.get();
  22.         totalTime = totalTime + f3.get();
  23.         totalTime = totalTime + f4.get();
  24.         System.out.println(totalTime);
  25.         prepareThreadPool.shutdown();
  26.     }

  27.     @Override
  28.     public Long call() throws Exception {
  29.         long start = System.currentTimeMillis();
  30.         Class.forName("oracle.jdbc.OracleDriver");
  31.         Connection conn = DriverManager.getConnection("jdbc:oracle:thin:127.0.0.1:1521:orcl", "edmond", "edmond");
  32.         int index = 0;
  33.         while (index < COUNT) {
  34.             PreparedStatement cmd = conn.prepareStatement("select * from t");
  35.             ResultSet rs = cmd.executeQuery();
  36.             while (rs.next()) {
  37.                 rs.getInt(1);
  38.             }
  39.             index++;
  40.             cmd.close();
  41.         }
  42.         long end = System.currentTimeMillis();
  43.         conn.close();
  44.         return end - start;

  45.     }

  46. }
先重新整理共享池
alter system flush shared_pool;
然後執行JAVA程式.結果如下
Wait
57448

使用如下SQL檢視Execute to Parse %

  1. set linesize 300;
  2. set pagesize 3000;
  3. col sql_text format a50;
  4. SELECT sql_id,sql_text, s.PARSE_CALLS, loads, executions, round((1 - s.PARSE_CALLS / executions) * 100,-1)||'%' AS Execute_to_Parse
  5. FROM v$sql s
  6. WHERE executions>10 and PARSING_SCHEMA_NAME=upper('edmond') and rownum<10
  7. ORDER BY executions desc ;
結果如下


然後修改JAVA程式,檢視軟軟解析的情況.(快取遊標,注意紅色的程式碼)

  1. import java.sql.Connection;
  2. import java.sql.DriverManager;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.Future;

  10. public class Test implements Callable<Long> {
  11.     private static int COUNT = 100000;

  12.     public static void main(String[] args) throws Exception {
  13.         ExecutorService prepareThreadPool = Executors.newFixedThreadPool(4);
  14.         Future<Long> f1 = prepareThreadPool.submit(new Test());
  15.         Future<Long> f2 = prepareThreadPool.submit(new Test());
  16.         Future<Long> f3 = prepareThreadPool.submit(new Test());
  17.         Future<Long> f4 = prepareThreadPool.submit(new Test());
  18.         System.out.println("Wait");
  19.         Long totalTime = 0L;
  20.         totalTime = totalTime + f1.get();
  21.         totalTime = totalTime + f2.get();
  22.         totalTime = totalTime + f3.get();
  23.         totalTime = totalTime + f4.get();
  24.         System.out.println(totalTime);
  25.         prepareThreadPool.shutdown();
  26.     }

  27.     @Override
  28.     public Long call() throws Exception {
  29.         long start = System.currentTimeMillis();
  30.         Class.forName("oracle.jdbc.OracleDriver");
  31.         Connection conn = DriverManager.getConnection("jdbc:oracle:thin:127.0.0.1:1521:orcl", "edmond", "edmond");
  32.         int index = 0;
  33.         PreparedStatement cmd = conn.prepareStatement("select * from t");
  34.         while (index < COUNT) {
  35.             ResultSet rs = cmd.executeQuery();
  36.             while (rs.next()) {
  37.                 rs.getInt(1);
  38.             }
  39.             index++;
  40.         }
  41.         cmd.close();
  42.         long end = System.currentTimeMillis();
  43.         conn.close();
  44.         return end - start;

  45.     }

  46. }
還是先重新整理共享池.
alter system flush shared_pool;
執行JAVA程式,可以看到執行速度提高了近一倍
Wait
29881

最後使用SQL查詢Execute to Parse %


可以看到AWR報表中的Execute to Parse引數和軟軟解析是相關的.

事實上,resin中介軟體JNDI的配置是這樣的
8
所以造成了Execute to Parse指標的不佳.

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

相關文章