--
Google 그룹스 'Korea Spring User Group' 그룹에 가입했으므로 본 메일이 전송되었습니다.
웹에서 이 토론을 보려면 https://groups.google.com/d/msg/ksug/-/hgCIbAH-t_QJ을(를) 방문하세요.
이 그룹에 게시하려면 ks...@googlegroups.com(으)로 이메일을 보내세요.
그룹에서 탈퇴하려면 ksug+uns...@googlegroups.com로 이메일을 보내주세요.
더 많은 옵션을 보려면 http://groups.google.com/group/ksug?hl=ko에서 그룹을 방문하세요.
그러나 MySQL에는 fetchSize가 예상처럼 동작하지 않습니다. 아래 URL에 자세히 설명이 되어 있는데요,
* Framework Cursor (cursor in MySql) : http://bleujin.tistory.com/152
* http://www.databasesandlife.com/reading-row-by-row-into-java-from-mysql/
간단하게 정리하면, MySQL에서는 fetchSize를 지정해봤자 거기에 상관없이 한방에 다 전체 건을 보내줍니다.
꽁수로 fetchSize를 Integer.MIN_VALUE로 지정하고, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY 옵션으로 쿼리를 날리면 '스트리밍'으로 부분적으로 결과를 전송해주긴 합니다. Spring Batch의 JdbcCursorItemReader도 아래와 같이 기본적으로 ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY로 지정해서 PreparedStatement를 생성합니다.
preparedStatement = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
그래서 JdbcCusorItemReader.setFetchSize(Integer.MIN_VALUE )만 지정되면 스트리밍 방식이 동작합니다.
그러나 이렇게 해도 한번에 몇건씩 fetch해 주는지까지는 제어가 안 됩니다. JDBC규약과도 어긋납니다.
java.sql.Statement의 javadoc에는 setFetchSize로 지정되는 값은 0보다 작으면 SQLException을 던진다고 적혀 있습니다. 그래서 이 방식을 계속 써도 될지도 불안하게 느껴집니다.
위와 같은 한계와 때문에 Mysql에서 대용량 조회를 할 때는 쿼리 조건으로 일정건수가 넘지 않게 제약하는 방식을 많이 써왔습니다. Spring Batch에서는 JdbcCursorItemReader보다는 JdbcPagingItemReader, IbatisPagingItemReader은 페이징처리 클래스를 쓰는 것입니다.
페이징 로직처리를 해주는 추상화된 클래스를 만들어 놓으면, 반복해서 같은 로직을 구현하지 않아도 되기는해서, 개발에 공수가 크게 더 들어가지는 않습니다.
MySQL에서 useCursorFetch 옵션사용
얼마전에 MySQL에서도 5.0.2버전 이상에서는 useCursorFetch라는 옵션을 사용하면 DB에서 cursor를 사용해서 fetchSize가 인식된다는 걸 알게 되었습니다. JDBC연결 url을 설정할 때 뒤에 useCursorFetch를 붙여주면 됩니다.
* MySQL을 JDBC로 연결할때 쿼리 결과를 여유있게 받기 :http://kang594.blog.me/40515882
* http://wiki.gxtechnical.com/commwiki/servlet/hwiki?Client+and+server+cursors+-+using+MySQL,
이 옵션을 사용한다면 MySQL에서도 한번의 쿼리로 대용량 쿼리 조회가 가능해집니다. 그런데 DBA께 문의해보니 DB서버에서는 메모리에 커서를 유지해야되니 서버 쪽에서는 좀 부담이 될 수도 있다고 합니다. 그리고 성능에도 쿼리를 여러번 던지는 편이 더 유리하다고 하네요. DB장비의 상황과 조회조건의 index활용 여부에 따라서 결정해야겠지만, 아예 옵션이 없었던 때보다는 선택의 여지가 넓어졌습니다. 물론 아무리 fetchSize를 지정을 한다고 도 sqlMapClient.queryForList 같은 메소드로 모든 건을 다 List에 쌓는다면 당연히 메모리 걱정을 해야 합니다 ^^;