Framework/Database2009. 3. 12. 16:31

이전 글을 작년 7월에 써서 올해 1월 12일날 포스팅을 해서 기억도 잘 안난다 -ㅅ-; (심지어 거기에 나온 내용들은 이미 7년전쯤에 해본 내용이다.)

  public void testStatic() throws Exception {
    DBManager dbm = new MSSQLPoolDBManager("com.microsoft.jdbc.sqlserver.SQLServerDriver", 
         
"jdbc:microsoft:sqlserver://novision:1433;DatabaseName=test", "bleu", "bleu") ;
    Connection conn = null;
    ResultSet rs = null;
    PreparedStatement pstmt = null;

    try {
      conn = dbm.getConnection()
      pstmt = conn.prepareStatement(getProcSQL());
      rs = pstmt.executeQuery()
      populate(rs)
    catch (SQLException ex) {
      throw ex;
    finally {
      closeWithoutException(rs);
      closeWithoutException(pstmt);
      dbm.freeConnection(conn)
    }
  }

  private String getProcSQL() {
    return "select custNo, fixLength from customer_tblc";
  }

  private void populate(ResultSet rowsthrows SQLException {
    int i = 0;

    while (rows.next() && i++ < 10) {
      System.out.print(rows.getString(1));
    }
    System.out.println();

  }

"위 평범한 JDBC 코드는 customer_tblc에서 10건을 가져와서 10건을 화면에 찍는 프로그램이다"
는 사실이 아니라는 걸 얘기 했었다.

위 코드를 default cursor인 Forward Only cursor로 실행하면(빨간색 화살표는 여러번 반복된다는 뜻)


   1. WAS는 쿼리 실행을 요청한다. 
   2-1. DBServer에서는 cusotmer_tblc의 row를 읽는대로 Working Memory에 올린다.
   2-2  동시에 WorkingMemory에 어느정도의 데이타가 쌓이면(대략 2-8k) 바로 WAS에 전송한다.
   2-3  WAS는 패킷을 받아서 받았다는 confirm 메시지를 전송한다. 

   위 2-1 ~ 2-3 과정은 DB가 쿼리의 모든 row를 읽을때까지 반복된다. 
   WAS에서는 사용하는 10건의 row를 받았고 이후의 데이타는 쓸모 없지만 주구장창 모두 받아야 한다. 
   3. WAS는 나머지 데이타도 모두 받아서 버린후에 DB close를 요청한다.
   DB서버는 WorkingMemory를 정리하고 close 된다.

만약 테이블에 단지 20건 정도라면 괜찮지만 1000000건만 되도 99.9999%의 비용을 더 소모하였다.

단점은
  - WAS에서 필요한 양과 상관없이 해당 쿼리의 모든 데이타를 읽어야 한다.(컴퓨터에게 읽는다는 의미는 하드에 있는 바이트 배열을 메모리에 복제하였다는 얘기이다.)
  - WAS에서 필요한 양과 상관없이 모든 데이타를 네트워크에 전송함으로서 막대한 네트워크 부하가 발생한다. 
  - 모든 데이타를 받아야 종료(DB Close) 할수 있다.

장점
   - 읽는대로 바로 바로 전송해버리기 때문에 DB 메모리가 많이 소모되지 않는다.
   - 네트워크에 전송할때 여러 row를 묶어서 패킷으로 전송한다.
   - 커서는 비동기적으로 작동하기 때문에 최소한의 정보 - 현재 커서의 위치 - 만을 유지할 수 있다.

  public void testStatic() throws Exception {
    Connection conn = null;
    ResultSet rs = null;
    PreparedStatement pstmt = null;

    try {
      conn = dbm.getConnection()
      pstmt = conn.prepareStatement(getProcSQL(), ResultSet.TYPE_SCROLL_INSENSITIVE
                                                , ResultSet.CONCUR_READ_ONLY)
;
      rs = pstmt.executeQuery()
      populate(rs)//
    catch (SQLException ex) {
      throw ex;
    finally {
      closeWithoutException(rs);
      closeWithoutException(pstmt);
      dbm.freeConnection(conn);
    }
  }

위와같이 insensitive cursor로 실행하면


  1. WAS는 쿼리 실행을 요청한다.  
  2. DB는 쿼리의 "모든" 결과를 메모리에 snapshot 형태로 만든다. 모든 데이타의 load를 완료하면 Client의 신호를 기다린다
  3. Client(WAS)는 Fetch(rs.next())를 요청한다.
  4. DB는 cursor 정보를 유지하면서 currentRow의 정보를 Client에게 보낸다. 
  5. 패킷(1개의 row만 들어있음)을 받았다는 confirm 메시지를 보낸다.
  3,4,5의 동작을 9번 더 반복한다
  
  6. WAS는 DB close를 요청한다.
  DB는 결과셋과 cursor정보를 메모리에서 삭제하고 연결정보를 close한다.  


ForwadOnly와 달리 3번, 4번, 5번은 비동기적으로 작동한다. 즉 모든 결과셋을 Snapshot형태로 메모리에 모두 올리고 나서야 Client의 Fetch(res.next())를 실행할 수 있다.(이동안 Client은 Hang 상태이다. 역시 이전 글의 네트웨크 모니터링 캡쳐화면과 같이 보도록 하자.)


단점은
  - WAS에서 필요한 양과 상관없이 해당 쿼리의 모든 데이타를 읽어야 한다.(컴퓨터에게 읽는다는 의미는 하드에 있는 바이트 배열을 메모리에 복제하였다는 얘기이다.)
  - DB에서 읽은 모든 Row를 결과셋에 Snapshot 형태로 저장해야 하기 때문에 공유 자원인 DB 메모리가 많이 소모된다. (이 메모리는 재사용되지 않는다. 즉 같은 프로그램을 2번 실행한다는 것은 SnapShot을 2번 유지한다는 것을 뜻한다. )
   - 동기적으로 작동하기 때문에 Client의 fetch 요구시마다 row단위의 데이타 전송이 이루어진다.(패킷의 크기가 작다.)
   - cursor를 해당 프로그램이 종료될때까지(DB close 할때까지) 유지해야 하고 더 많은 정보를 관리해야 한다.
   - 첫번째 Row가 Client에 전송되는 시간이 느리다.


장점 
   - Client가 필요한 양만 네트워크에 전송한다. 


단점이 너무 심각해 보이는 위 두가지 경우는 황당해 보이겠지만 90% 이상의 사이트에서 발생하고 있는 현실이다. 말 그대로 불편한 진실인 것이다. (이 블로그에서 소개하는 DB Framework는 위 방식으로 작동하지 않는다.)


커서의 종류는 보통 ForwardOnly, Static, Keyset, Dynamic 네가지 종류가 있으며 JDBC 코드로는 작성하기는 어렵지만 다음에는 나머지 두개의 커서의 실행과정도 분석해 보자. (앞서 언급했듯이 JDBC에는 커서를 지정한다기 보다 다른 선택에 의해 자동 종속되고 Keyset과 Dynamic가 종속되는 경우는 극히 드물다. 반면에 C#등의 MS 계열은 커서 모드를 설정할 수 있도록 하고 있다. 다만 일부 조건을 만족시켜야 된다.)






'Framework > Database' 카테고리의 다른 글

Framework (Servant)  (0) 2009.03.12
Framework (DBController)  (0) 2009.03.12
Framework (Handler)  (0) 2009.03.08
Framework (Rows)  (0) 2009.03.07
Framework (IQueryable)  (0) 2009.03.06
Posted by bleujin