for(;;){
EXEC ORACLE OPTION (HOLD_CURSOR=YES);
EXEC ORACLE OPTION (RELEASE_CURSOR=NO);
EXEC SQL INSERT ...... ; // SQL 수행
EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
}
call count cpu elapsed disk query current rows --------- -------- -------- ---------- -------- --------- ------------ -------- Parse 1 0.00 0.00 0 0 0 0 Execute 5000 0.18 0.14 0 0 0 0 Fetch 5000 0.17 0.23 0 10000 0 5000 --------- -------- -------- ---------- -------- --------- ------------ -------- total 10001 0.35 0.37 0 10000 0 5000 Misses in library cache during parse: 1
public static void main(String[] arr) throws SQLException, Exception{
// (1) Bind 변수를 사용하지 않을 때
noBinding(connMgr.getConnectionMethod(), 5000);
// (2) Bind 변수를 사용하지만, Caching 옵션을 사용하지 않을 때
noCaching(connMgr.getConnectionMethod(), 5000);
// (3) Cursor를 닫지 않고 반복적으로 재사용할 때
cursorHolding(connMgr.getConnectionMethod(), 5000);
// (4) Caching 옵션을 사용할 때
cursorCaching(connMgr.getConnectionMethod(), 5000);
}
public static void noBinding(Connection conn, int count)throws Exception{
PreparedStatement stmt;
ResultSet rs;
for(int i = 1; i <= count; i++){
stmt = conn.prepareStatement(
"SELECT /* no_binding */" + i + ", " + i + ", 'test', a.* " +
"FROM emp a WHERE a.ename LIKE 'W%'");
rs = stmt.executeQuery();
rs.close();
stmt.close();
}
}
******************************************************************************** SELECT /* no_binding */1, 1, 'test', a.* FROM emp a WHERE a.ename LIKE 'W%' call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.01 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 7 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3 0.00 0.01 0 7 0 1 Misses in library cache during parse: 1 ******************************************************************************** SELECT /* no_binding */2, 2, 'test', a.* FROM emp a WHERE a.ename LIKE 'W%' call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 7 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3 0.00 0.00 0 7 0 1 Misses in library cache during parse: 1 ******************************************************************************** . . . 5000번까지 동일 ******************************************************************************** SELECT /* no_binding */5000, 5000, 'test', a.* FROM emp a WHERE a.ename LIKE 'W%' call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 7 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 3 0.00 0.00 0 7 0 1 Misses in library cache during parse: 1 ********************************************************************************
public static void noCaching(Connection conn, int count)throws Exception{
PreparedStatement stmt;
ResultSet rs;
for(int i = 1; i <= count; i++){
stmt = conn.prepareStatement(
"SELECT /* no_caching */ ?, ?, ?, a.* " +
"FROM emp a WHERE a.ename LIKE 'W%'");
stmt.setInt(1, i);
stmt.setInt(2, i);
stmt.setString(3, "test");
rs = stmt.executeQuery();
rs.close();
stmt.close();
}
}
******************************************************************************** SELECT /* no_caching */ :1, :2, :3, a.* FROM emp a WHERE a.ename LIKE 'W%' call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 5000 0.00 0.28 0 0 0 0 Execute 5000 0.01 0.84 0 0 0 0 Fetch 5000 0.00 1.11 0 35000 0 5000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 15000 0.01 2.24 0 35000 0 5000 Misses in library cache during parse: 1 ********************************************************************************
public static void cursorHolding(Connection conn, int count)throws Exception{
// PreparedStatement를 루프문 바깥에 선언.
PreparedStatement stmt = conn.prepareStatement(
"SELECT /* cursor_holding */ ?, ?, ?, a.* " +
"FROM emp a WHERE a.ename LIKE 'W%'");
ResultSet rs;
for(int i = 1; i <= count; i++){
stmt.setInt(1, i);
stmt.setInt(2, i);
stmt.setString(3, "test");
rs = stmt.executeQuery();
rs.close();
}
// 루프를 빠져 나왔을 때 커서를 닫는다.
stmt.close();
}
******************************************************************************** SELECT /* cursor_holding */ :1, :2, :3, a.* FROM emp a WHERE a.ename LIKE 'W%' call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 5000 0.01 1.43 0 0 0 0 Fetch 5000 0.01 0.70 0 35000 0 5000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 10001 0.02 2.15 0 35000 0 5000 Misses in library cache during parse: 1 ********************************************************************************
public static void cursorCaching(Connection conn, int count)throws Exception{
// 캐시 사이즈를 1로 지정
((OracleConnection)conn).setStatementCacheSize(1);
// 묵시적 캐싱 기능을 활성화
((OracleConnection)conn).setImplicitCachingEnabled(true);
for(int i = 1; i <= count; i++){
PreparedStatement stmt = conn.prepareStatement(
"SELECT /* implicit_caching */ ?, ?, ?, a.* " +
"FROM emp a WHERE a.ename LIKE 'W%'");
stmt.setInt(1, i);
stmt.setInt(2, i);
stmt.setString(3, "test");
ResultSet rs = stmt.executeQuery();
rs.close();
// 커서를 닫지만 내부적으로는 닫히지 않은 채 캐시에 보관
stmt.close();
}
}
******************************************************************************** SELECT /* implicit_caching */ :1, :2, :3, a.* FROM emp a WHERE a.ename LIKE 'W%' call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.04 0 0 0 0 Execute 5000 0.01 1.35 0 0 0 0 Fetch 5000 0.00 0.68 0 35000 0 5000 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 10001 0.01 2.08 0 35000 0 5000 Misses in library cache during parse: 1 ********************************************************************************
Dynamic SQL 사용 시, 커서 캐싱(10g 이후) | |||
---|---|---|---|
10g 이후부터 같은 SQL문을 연속적으로 실행하면, Dynamic SQL 이더라도 바로 직전 커서를 캐싱합니다.(Ref Cursor일 때는 제외) Static SQL과 마찬가지로, 이 기능도 session_cached_cursors 파라미터가 0보다 클 때만 작동합니다. # 아래는 system 계정으로 테스트를 했습니다. SQL> alter session set session_cached_cursors = 100; Session altered. SQL> create table t ( x number); Table created. SQL> alter system flush shared_pool; System altered. SQL> declare 2 i number; 3 begin 4 for i in 1..100 5 loop 6 execute immediate 'insert into t values(' \ | | mod(i, 10) || ')'; 7 end loop; 8 9 commit; 10 end; 11 / PL/SQL procedure successfully completed. SQL> select count(distinct sql_text) sql_cnt 2 , sum(parse_calls) parse_calls 3 , sum(executions) executions 4 from v$sql 5 where sql_text like 'insert into t values%'; SQL_CNT PARSE_CALLS EXECUTIONS \ \ --\- \ \- 10 100 100 > 0부터 9까지의 값을 입력하는 10개 SQL을 불연속적으로 실행했더니 Parse Call이 SQL 수행횟수만큼 발생했습니다. SQL> alter system flush shared_pool; System altered. SQL> declare 2 i number; 3 begin 4 for i in 1..100 5 loop 6 execute immediate 'insert into t values(' \ | | ceil(i/10) || ')'; 7 end loop; 8 9 commit; 10 end; 11 / PL/SQL procedure successfully completed. SQL> select count(distinct sql_text) sql_cnt 2 , sum(parse_calls) parse_calls 3 , sum(executions) executions 4 from v$sql 5 where sql_text like 'insert into t values%'; SQL_CNT PARSE_CALLS EXECUTIONS \ \ --\- \ \- 10 10 100 > 1부터 10개까지의 값을 입력하는 10개 SQL을 연속적으로 입력했더니 Parse Call이 SQL 개수만큼 발생했습니다. SQL> alter session set session_cached_cursors = 0; Session altered. SQL> alter system flush shared_pool; System altered. SQL> declare 2 i number; 3 begin 4 for i in 1..100 5 loop 6 execute immediate 'insert into t values(' \ | | ceil(i/10) || ')'; 7 end loop; 8 9 commit; 10 end; 11 / PL/SQL procedure successfully completed. SQL> select count(distinct sql_text) sql_cnt 2 , sum(parse_calls) parse_calls 3 , sum(executions) executions 4 from v$sql 5 where sql_text like 'insert into t values%'; SQL_CNT PARSE_CALLS EXECUTIONS \ \ --\- \ \- 10 100 100 > 1부터 10가지의 값을 입력하는 10개 SQL을 연속적으로 입력했지만 세션 커서 캐싱 기능을 비활성화시켰더니 Parse Call이 SQL 수행 횟수만큼 발생했습니다. |
Instance Efficiency Percentages (Target 100%) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Buffer Nowait %: 99.98 Redo NoWait %: 100.00 Buffer Hit %: 97.93 In-memory Sort %: 100.00 Library Hit %: 99.55 Soft-Parse %: 98.34 Execute to Parse %: 89.31 Latch Hit %: 98.67 Parse CPU to Parse Elapsd %: 61.11 % Non-Parse CPU: 97.58
이 자료는 (오라클 성능 고도화 원리와해법 I)을 참고 하여 작성했습니다.