8. 애플리케이션 커서 캐싱
2010.06.29 14:11
세션커서캐싱을 이용 하면 SGA이 공유 커서를 빠르게 찾아서 커서를 오픈 할 수 있다.
그렇다하더라도, 공유 커서 힙을 Pin 하고 실행에 필요한 메모리 공간을 PGA에 할당하는 등의 작업은 반복하게 한다.
애플리케이션 커서 캐싱을 이용하여 이 과정마저 생략하는 것이 가능하다.
- 패턴① : 바인드 변수를 사용하지 않을 때.
- 패턴② : 바인드 변수를 사용, 커서캐싱을 하지 않을 때.
- 패턴③ : 커서를 닫지 않고 재사용할 때.
- 패턴④ : 묵시적 캐싱 기능을 사용할 때.
각각의 패턴을 Java를 예로 살펴 보자.
패턴① 바인드 변수를 사용하지 않을 때.
/**
* 패턴1.
*/
public static void noBinding(Connection conn) throws Exception {
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = null;
for (int i = 1 ; i <= 5000; i++ ) {
sql = "SELECT /* no_biding */ " + i + "," + i + ",'test',a.* FROM scott.emp a WHERE a.ename LIKE 'W%'";
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
rs.close();
stmt.close();
}
}
위 소스를 보면 SQL문이 계속 변하는 것을 알 수 있다.
select /* no_binding */ 1,1,'test',a.* FROM scott.emp a WHERE a.ename LIKE 'W%'
select /* no_binding */ 2,2,'test',a.* FROM scott.emp a WHERE a.ename LIKE 'W%'
select /* no_binding */ 3,3,'test',a.* FROM scott.emp a WHERE a.ename LIKE 'W%'
.
.
.
select /* no_binding */ 5000,5000,'test',a.* FROM scott.emp a WHERE a.ename LIKE 'W%'
즉, 하드파싱이 대입값만큼 발생 (1~5000)
패턴② 바인드 변수를 사용、커서캐싱을 하지않을때.
/**
* 패턴2.
*/
public static void noCaching(Connection conn) throws Exception {
PreparedStatement stmt = null;
ResultSet rs = null;
String sql = null;
for (int i = 1 ; i <= 5000; i++ ) {
sql = "SELECT /* no_biding */ ?,?,?,a.* FROM scott.emp a WHERE a.ename LIKE 'W%'";
stmt = conn.prepareStatement(sql);stmt.setInt(1, i);
stmt.setInt(2, i);
stmt.setString(3, "test");
rs = stmt.executeQuery();rs.close();
stmt.close(); // 커서를 닫음.
}
}
위 소스를 보면 SQL문은 한개로 해결. 바인드값만이 변함.
select /* no_binding */ ?,?,?,a.* FROM scott.emp a WHERE a.ename LIKE 'W%'
즉, 하드파싱이 한번만 일어난다.
그러나, 루프내에서 커서를 닫아, 항상 커서를 생성하게 된다.
- Parse Count : 5000
- Execute Count : 5000
- Fetch Count : 5000
패턴③ 커서를 닫지 않고 재사용할 경우.
/**
* 패턴3.
*/
public static void cursorHolding(Connection conn) throws Exception {
PreparedStatement stmt = null;
String sql = "SELECT /* no_biding */ ?,?,?,a.* FROM scott.emp a WHERE a.ename LIKE 'W%'";stmt = conn.prepareStatement(sql);
ResultSet rs = null;
for (int i = 1 ; i <= 5000; i++ ) {
stmt.setInt(1, i);stmt.setInt(2, i);
stmt.setString(3, "test");
rs = stmt.executeQuery();rs.close();
}
stmt.close(); // 루프가 끝나면 커서를 닫는다.}
위 소스를 보면 SQL문은 한개로 해결. 바인드값만이 변함.
select /* no_binding */ ?,?,?,a.* FROM scott.emp a WHERE a.ename LIKE 'W%'
즉, 하드파싱이 한번만 일어난다.
또한, 커서를 루프가 종료후에 닫고 있다. 이것을 애플리케이션 커서 라 한다.
- Parse Count : 1
- Execute Count : 5000
- Fetch Count : 5000
패턴④ 묵시적 캐싱을 사용할 경우.
/**
// 캐시 사이즈를 1로 지정
* 패턴4.
*/
public static void cursorCaching(Connection conn) throws Exception {((OracleConnection) conn).setStatementCacheSize(1);
// 묵시적 캐싱 기능을 활성화
((OracleConnection) conn).setImplicitCachingEnabled(true);
PreparedStatement stmt = null;
ResultSet rs = null;
for (int i = 1 ; i <= 5000; i++ ) {
String sql = "SELECT /* no_biding */ ?,?,?,a.* FROM scott.emp a WHERE a.ename LIKE 'W%'";stmt = conn.prepareStatement(sql);
stmt.setInt(1, i);
stmt.setInt(2, i);
stmt.setString(3, "test");
rs = stmt.executeQuery();
rs.close();
stmt.close(); // 루프가 끝나면 커서를 닫는다. 그러나, 내부적으로는 닫지않고 캐시에 보관
}
}
위 소스를 보면 패턴②와 같은 형태를 하면서도 사실상 패턴③과 같은 성능을 보인다.
즉, JDBC의 API에서 제공하는 기능을 이용하여 매번 커서를 닫는듯한 코딩을 해도 내부적으로는 세션커서캐싱을 한다.- Parse Count : 1
- Execute Count : 5000
- Fetch Count : 5000
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
27 | 5. V$SYSSTAT [1] | 토시리 | 2010.06.14 | 9849 |
26 | 1. 블록 단위 I/O | 토시리 | 2010.07.12 | 9381 |
25 | 4. 커서 공유 | balto | 2010.06.28 | 9200 |
24 | 3. Single Block vs. Multiblock I/O | 휘휘 | 2010.07.12 | 9172 |
23 | 2. User Call vs. Recursive Call | 토시리 | 2010.07.07 | 9050 |
22 | 10. Dynamic SQL 사용 기준 | balto | 2010.07.04 | 8643 |
21 | 1. 트랜잭션 동시성 제어 | 실천하자 | 2010.05.31 | 8632 |
20 | 2. AutoTrace | 실천하자 | 2010.06.06 | 8599 |
19 | 3. 비관적 vs. 낙관적 동시성 제어 | 휘휘 | 2010.06.07 | 8210 |
18 | 9. Snapshot too old | balto | 2010.05.30 | 8102 |
17 | 11. End-To-End 성능관리 | 휘휘 | 2010.06.14 | 8095 |
16 | 7. Response Time Analysis 방법론과 OWI | balto | 2010.06.13 | 8067 |
15 | 10. 대기 이벤트 | balto | 2010.05.30 | 8012 |
14 | 8. I/O 효율화 원리 | 휘휘 | 2010.07.19 | 7742 |
13 | 2. Memory vs. Disk I/O | 휘휘 | 2010.07.12 | 7439 |
12 | 부록 | 휘휘 | 2010.07.19 | 7238 |
11 | 1. SQL과 옵티마이저 | 휘휘 | 2010.06.28 | 7218 |
10 | 12. 데이터베이스 성능 고도화 정석 해법 | 휘휘 | 2010.06.14 | 7153 |
9 | 4장. 라이브러리 캐시 최적화 원리 | 휘휘 | 2010.06.28 | 6915 |
8 | 2장. 트랜잭션과 Lock | 운영자 | 2010.06.01 | 6896 |