대용량 업데이트 시 속도 향상을 위해 batch를 사용하여 insert/update를 한다.
ojdbc.jar에 있는 ORACLE 전용 batch를 사용하면 더 빠른 수행결과를 보여주나
iBatis에서는 Java에 있는 batch 방법만을 사용할 수 있다.
하지만 대용량의 데이터를 한번에 executeBatch() 해준다면 서버에 메모리를 많이 사용하게 되어 메모리 부족현상이 발생할 수 있다.
그래서 5~30 (Oracle에서 제시한 배치 size라고 함)를 한 묶음으로 배치 처리해주는 것이 효율적이다.
임시테이블에 컬럼 2개를 생성하여 10만건을 insert/update를 해본 결과
배치 크기를 30으로 줬을 땐 약 5.5초가 걸렸고
배치 크기를 1000으로 줬을 땐 약 4초가 걸렸다.
참고로 배치 사용 안하면 약 30초가 걸렸다.
※ 배치 사용할 시 테이블에 인덱스를 사용안하면 일반 업데이트와 큰 차이가 없다.
IbatisTest.java
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.springframework.util.StopWatch;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
public class IbatisTest {
private static final Logger log = Logger.getLogger(IbatisTest.class);
private static SqlMapClient sqlMapper;
private static StopWatch stopWatch = new StopWatch("IbatisTest");
static {
try {
Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);
reader.close();
} catch (IOException e) {
throw new RuntimeException("Something bad happened while building the SqlMapClient instance." + e, e);
}
}
public static void updateTest() throws SQLException {
stopWatch.start("updateTest");
sqlMapper.startTransaction();
sqlMapper.startBatch();
Map<String, Object> params = new HashMap<String, Object>();
for (int i = 1; i <= 100000; i++) {
params.put("seq", i);
params.put("content", "HELLO");
sqlMapper.update("updateTest", params);
if (i % 30 == 0) {
sqlMapper.executeBatch();
sqlMapper.startBatch();
}
}
sqlMapper.executeBatch();
sqlMapper.commitTransaction();
sqlMapper.endTransaction();
stopWatch.stop();
log.info(stopWatch.prettyPrint());
}
public static void main(String[] args) throws Exception {
updateTest();
}
}
IbatisTest.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="ibatisTest">
<update id="updateTest" parameterClass="map">
MERGE INTO TEST
USING DUAL
ON (
SEQ = #seq#
)
WHEN MATCHED THEN
UPDATE SET CONTENT = #content# || #seq#
WHEN NOT MATCHED THEN
INSERT (SEQ, CONTENT)
VALUES (#seq#, #content#)
</update>
</sqlMap>
SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings
cacheModelsEnabled="true"
enhancementEnabled="true"
lazyLoadingEnabled="true"
useStatementNamespaces="false"
/>
<transactionManager type="JDBC">
<dataSource type="DBCP">
<property name="JDBC.Driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="JDBC.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:orcl" />
<property name="JDBC.Username" value="hr" />
<property name="JDBC.Password" value="hr" />
<property name="Pool.MaximumActiveConnections" value="10" />
<property name="Pool.MaximumIdleConnections" value="5" />
<property name="Pool.MaximumWait" value="60000" />
<property name="Pool.ValidationQuery" value="SELECT 1 FROM DUAL" />
<property name="Pool.LogAbandoned" value="false" />
<property name="Pool.RemoveAbandoned" value="false" />
<property name="Pool.RemoveAbandonedTimeout" value="50000" />
<property name="Driver.DriverSpecificProperty" value="SomeValue" />
</dataSource>
</transactionManager>
<sqlMap resource="ibatis/IbatisTest.xml" />
</sqlMapConfig>
log4j.properties
log4j.rootLogger=INFO, stdout
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss} - %m%n
사용된 라이브러리
cglib-nodep-2.2.3.jar
commons-collections-3.2.1.jar
commons-dbcp-1.4.jar
commons-logging-1.1.1.jar
commons-pool-1.6.jar
ibatis-2.3.4.726.jar
log4j-1.2.17.jar
ojdbc6.jar
oscache-2.4.1.jar
spring.jar
순수 Java 코딩이라면 OracleConnection과 OraclePrepareStatement를 사용하는 batch 방법을 추천한다. 이 방식이 더 빠르다.
끝.
'DB' 카테고리의 다른 글
Centos 7 기준 redis 5.0.3 tar server 실행 (0) | 2018.12.31 |
---|---|
디비툴 DBeaver (0) | 2016.06.25 |
MySQL 5.1 사용자(계정) 추가 (0) | 2012.02.04 |
SQL로 카테고리, 트리, 계층 구조의 구현 (0) | 2011.10.18 |
Apache Derby (더비) (0) | 2011.09.11 |
댓글