출판사의 동의를 얻어서 일부 섹션을 공개합니다. 프로모션도 겸하고, 심혈을 기울인 내용이 시간 속에 파묻혀 버리지 않기를 바라는 마음으로 올립니다. 도움을 주신 한빛미디어 출판사의 임성춘 팀장님께 감사드립니다. |
발췌: 모델2로 다시 배우는 JSP, 7장, p252 |
일정한 형태의 반복적인 데이터를 입력할 때, DBMS마다 구조적인 차이가 있어서 결과가 제각각이지만 오라클의 경우 PreparedStatement와 batch관련 메소드의 조합은 아주 환상적인 결과를 가져온다. BMT(BenchMark Test)를 이용해서 알아보았다.
jdk1.3 버전부터 추가된 것이 있는데, Statement를 일괄적으로 처리할 수 있도록 한 것이다. addBatch() 메소드와 executeBatch() 라는 메소드를 사용해서 위 소스를 다음과 같이 바꿔보았다.
[예제 7-1] jdbc09.jsp |
… 이전 생략 … %>start:<%=System.currentTimeMillis()-sTime%><hr><% // 반복 15000회 for(int i=0; i<15000; i++) { // 쿼리를 만들어서 실행한다. queryBuf.setLength(0); queryBuf.append("INSERT INTO TEST_TABLE (SEQ, SUBJECT) VALUES ( " ) .append(i).append(", '이 행은 ") .append(i).append(" 번째 입력되었습니다.' ) "); // 배치에 추가한다. stmt.addBatch(queryBuf.toString()); } // end for %>before batch job :<%=System.currentTimeMillis()-sTime%><% // 저장된 쿼리를 한꺼번에 실행시킨다. stmt.executeBatch(); %><hr>end:<%=System.currentTimeMillis()-sTime%><% // Statement를 닫는다. stmt.close(); … 이하 생략 … |
모델2로 다시 배우는 JSP |
생략된 부분은 jdbc07.jsp 소스와 동일하다. 변경된 부분은 반복문 안에서 생성된 쿼리를 executeUpdate(String) 메소드를 수행하는 대신에 stmt 인스턴스에 추가해주는 addBatch(스트링) 메소드를 실행하고 반복이 완료되면 executeBatch() 메소드를 수행해서 한꺼번에 몰아주는 작업을 한다.
PreparedStatement에서 배치작업을 하려는 경우 다음과 같이 소스가 바뀌게 된다.
[예제 7-2] jdbc10.jsp |
… 이전 생략 … // 반복 15000회 for(int i=0; i<15000; i++) { // 쿼리를 실행한다. pstmt.setInt(1, i); pstmt.setInt(2, i); // 배치에 추가한다. pstmt.addBatch(); } // end for %>before batch job :<%=System.currentTimeMillis()-sTime%><% // 저장된 쿼리를 한꺼번에 실행시킨다. pstmt.executeBatch(); %><hr>end:<%=System.currentTimeMillis()-sTime%><% … 이하 생략 … |
생략된 부분은 jdbc08.jsp 소스와 동일하다. 마찬가지로 반복문 안에서는 addBatch() 메소드를 통해서 pstmt 인스턴스에 추가하는 작업을 수행하고, 반복이 끝나면 한번에 밀어주는 executeBatch() 메소드를 수행한다. 실행결과는 아주 놀라웠다.
|
[그림 7-1] Statement의 executeBatch() 사용 |
|
[그림 7-2] PreparedStatement 의 executeBatch() 사용 |
executeBatch() 처리 시 실행시간은 극과 극이었다. 일단 Statement의 배치결과를 보자. jsp에서 반복문을 수행하는 시간은 62밀리초 밖에 안걸렸고, executeBatch()를 통해서 DB에서 돌아가는 시간을 기다린 것이 33초가 소요되었다. 따지고 보면 노가다는 톰캣이 아니라 오라클의 몫이라는 얘기다. 전체적으로 따지면 배치를 하는 것이나 안하는 것이나 크게 차이가 나지 않았다.
하지만, PreparedStatement에서 배치작업은 얘기가 다르다. 테스트하면서 눈이 의심스러워서 몇 번이고 다시 해봤다. 테이블을 삭제하는 구문에 주석을 달아 남겨두어서 db에 들어가 확인을 해보니 정상적으로 데이터가 들어가 있었다. 33초 걸리던 일을 0.59초만에 해낸다는 것은 획기적인 일이 아닐 수 없다. 10배수인 150,000건을 돌려도 10초 전후로 완료되었다.
주의: 이 책의 테스트는 오라클 8.1.7에 국한된 것으로 필자가 mysql 3.23.53-max-nt에서 테스트한 결과는 판이하게 달랐다. Statement와 PreparedStatement의 차이가 거의 없었고, 거의 동일한 결과를 가져왔다. DBMS의 내부구조상의 차이로 인한 결과이기 때문에 각각의 서버에서도 테스트를 한 후에 빠른 경우를 찾아서 적용하기 바란다. |
소스 : ex07-01-01.zip