개발을 하다보면 API 호출 시 1000건이상의 데이터를 삽입해야하는 상황이 있습니다.
1000건의 데이터를 insert하는데 걸리는 시간은 약 5초였으며 시간을 줄일 수 있는 방안을 생각해봤는데요.
mybatis에서 대량의 데이터를 한번에 삽입할 수 있도록 insert foreach문(DBMS마다 지원하는 쿼리가 다름)을 지원하는 것을 알게 되었습니다.
수정 전 SQL
<insert id="add" parameterType="com.dto.Receiver$Info">
insert into tb_receiver(receiver_key, token, user_id, amount, is_received, receiver_date)
values(#{receiver_key}, #{token}, #{user_id}, #{amount}, #{is_received}, #{receiver_date})
</insert>
수정 후 SQL
<insert id="addList" parameterType="com.dto.Receiver$Info">
insert into tb_receiver(receiver_key, token, user_id, amount, is_received, receiver_date)
values
<foreach collection="list" index="index" item="receiver" separator=",">
(
#{receiver.receiver_key},
#{receiver.token},
#{receiver.user_id},
#{receiver.amount},
#{receiver.is_received},
#{receiver.receiver_date}
)
</foreach>
</insert>
기존방식에서 bulk insert 방식으로 변경 시 성능향상이 얼마만큼 되는지 JUnit 테스트를 진행해봤습니다.
테스트코드
@Autowired
ReceiverDao receiverDao;
@Autowired
SpreadService spreadService;
private final int peopleCnt = 7000;
@Test
public void 벌크_인석트_테스트() {
long amount = 1000000;
long[] amounts = spreadService.distribute(amount, peopleCnt);
List<Receiver.Info> listReceiver = new ArrayList<Receiver.Info>();
//뿌리기 받을사람 정보 추가
for(int i=0; i<amounts.length; i++) {
Receiver.Info receiver = new Receiver.Info();
receiver.setToken("AsD");
receiver.setAmount(amounts[i]);
receiver.setReceiver_key(SeedUtil.createUUID());
receiver.setIs_received("0");
receiver.setReceiver_date(new Date());
listReceiver.add(receiver);
}
int result = receiverDao.addList(listReceiver);
assertThat(result, is(peopleCnt));
}
@Test
public void 단일_인석트_테스트() {
long amount = 1000000;
int sum = 0, result = 0;
long[] amounts = spreadService.distribute(amount, peopleCnt);
//뿌리기 받을사람 정보 추가
for(int i=0; i<amounts.length; i++) {
Receiver.Info receiver = new Receiver.Info();
receiver.setToken("Asq");
receiver.setAmount(amounts[i]);
receiver.setReceiver_key(SeedUtil.createUUID());
receiver.setIs_received("0");
receiver.setReceiver_date(new Date());
result = receiverDao.add(receiver);
sum += result;
}
assertThat(sum, is(peopleCnt));
}
테스트는 다음과 같이 진행했습니다.
삽입하려는 데이터의 건수는 1,000건부터 8,000건까지 1,000단위로 테스트 진행
1,000건
2,000건
건수 | single insert | bulk insert |
1,000건 | 약 5초 | 약 0.7초 |
2,000건 | 약 7초 | 약 1초 |
3,000건 | 약 9초 | 약 1초 |
4,000건 | 약 12초 | 약 1.5초 |
5,000건 | 약 14초 | 약 1.5초 |
6,000건 | 약 17초 | 약 2초 |
7,000건 | 약 20초 | 약 2.2초 |
8,000건 | 약 25초 | 약 2.2초 |
* 테스트결과는 컴퓨터 사양에 따라 달라질 수 있습니다.
* bulk insert를 이용하여 10,000건 이상 삽입 시 성능이 좋지 않을경우에는 일정 건수로 분할하여 삽입하거나 엑셀파일로 export한 후 DBMS에서 엑셀파일을 읽는 방식으로 진행하는 방안도 존재합니다.
'Spring' 카테고리의 다른 글
Spring log4j 라이브러리란? (0) | 2021.03.25 |
---|---|
Springframework version 마이그레이션하는 방법 (0) | 2021.03.25 |
SELECT 문으로 데이터 랜덤으로 가져올 경우에 대한 성능 테스트 (0) | 2020.12.05 |
멀티 스레드 환경에서 동일 데이터에 대해서 업데이트 시 고려해야 할 사항 (0) | 2020.12.05 |
@Service, @Controller, @Repository 과 @Component의 차이는? (0) | 2020.12.03 |