메뉴 건너뛰기

bysql.net

8. 애플리케이션 커서 캐싱

2010.06.29 14:11

토시리 조회 수:6609

세션커서캐싱을 이용 하면 SGA이 공유 커서를 빠르게 찾아서 커서를 오픈 할 수 있다.
그렇다하더라도, 공유 커서 힙을 Pin 하고 실행에 필요한 메모리 공간을 PGA에 할당하는 등의 작업은 반복하게 한다.

애플리케이션 커서 캐싱을 이용하여 이 과정마저 생략하는 것이 가능하다.



  1. 패턴① : 바인드 변수를 사용하지 않을 때.
  2. 패턴② : 바인드 변수를 사용, 커서캐싱을 하지 않을 때.
  3. 패턴③ : 커서를 닫지 않고 재사용할 때.
  4. 패턴④ : 묵시적 캐싱 기능을 사용할 때.

각각의 패턴을 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


패턴④ 묵시적 캐싱을 사용할 경우.


    /**
     * 패턴4.
     */
    public static void cursorCaching(Connection conn) throws Exception {

        // 캐시 사이즈를 1로 지정

        ((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







번호 제목 글쓴이 날짜 조회 수
67 Front Page file 운영자 2010.05.17 154865
66 4. Prefetch file balto 2010.07.10 28434
65 5. 오라클 Lock file 휘휘 2010.06.07 26365
64 2. DB 버퍼 캐시 file 휘휘 2010.05.24 21916
63 3. SQL 트레이스 file balto 2010.06.06 21175
62 1. 기본 아키텍처 [1] file 휘휘 2010.05.23 19899
61 2. 트랜잭션 수준 읽기 일관성 file 휘휘 2010.06.07 19568
60 5. Undo file 토시리 2010.05.31 18650
59 11. Shared Pool file 실천하자 2010.05.31 18511
58 9. Static vs. Dynamic SQL [1] balto 2010.07.04 18343
57 4. Array Processing 활용 file 휘휘 2010.07.05 18238
56 1 장. 오라클 아키텍처 운영자 2010.05.20 17842
55 5. Fetch Call 최소화 file 휘휘 2010.07.05 16839
54 9. ASH(Active Session History) 실천하자 2010.06.14 15607
53 2. SQL 처리과정 file 휘휘 2010.06.28 15340
52 3. 버퍼 Lock [1] 휘휘 2010.05.24 15225
51 6. 바인드 변수의 부작용과 해법 file 실천하자 2010.06.28 14664
50 1. Explain Plan 실천하자 2010.06.06 14663
49 8. PL/SQL 함수 호출 부하 해소 방안 토시리 2010.07.11 14023
48 7. Result 캐시 휘휘 2010.07.19 12969