테스트 환경에서
벌크 쿼리를 사용해
성능을 개선한 경험을
담았습니다. 🙆🏻♂️
개선할 점
테스트 코드에서 데이터베이스(MySQL)에 데이터를 저장할 때, 반복문을 사용하여 데이터 저장을 수행했습니다. 하지만 반복문이 실행되는 횟수만큼 쿼리가 실행되기 때문에, 예를 들어 100만 건의 데이터를 저장할 경우, 100만 번의 쿼리가 실행됩니다. 이는 저장할 데이터와 쿼리 실행 횟수가 1:1 비율로 증가하여 매우 비효율적이라고 생각합니다.
개선한 방법
벌크 쿼리(Bulk Query)를 사용하여 만 건의 데이터를 한 번의 쿼리로 처리했습니다. 이를 통해 데이터 저장 시 쿼리 실행 횟수를 줄이고 성능을 크게 향상시킬 수 있었습니다.
벌크 쿼리 사용전 코드
@Test
void not_use_bulkInsert() throws Exception{
//given
EasyRandom easyRandom = PostFactory.get(3L, LocalDate.of(2024,1,1), LocalDate.of(2024, 2,2));
//when
List<Post> posts =IntStream.range(0, 10000)
.mapToObj(i -> easyRandom.nextObject(Post.class)).toList();
stopWatch.start();
for(Post post : posts) {
postRepository.save(post);
}
stopWatch.stop();
//then
System.out.println("실행 시간 : " + stopWatch.getTotalTimeSeconds());
}
EasyRandom은 설정해준 임의의 값의 범위 내에서 랜덤한 문자, 숫자와 같은 값으로 임의의 엔티티를 만들어주는 역할을 합니다.
데이터(만건)를 저장하는데 걸린 시간은 로컬 환경 기준으로 총 85s이 걸립니다.
벌크 쿼리 사용 후 코드
@SpringBootTest
public class PostInsertTest {
@Autowired
private PostRepository postRepository;
@Test
@DisplayName("대용량 데이터 넣기")
void bulkInsert() throws Exception{
//given
EasyRandom easyRandom = PostFactory.get(3L, LocalDate.of(2024,1,1), LocalDate.of(2024, 2,2));
StopWatch stopWatch = new StopWatch();
//when
List<Post> posts = IntStream.range(0, 10000)
.mapToObj(i -> easyRandom.nextObject(Post.class)).toList();
stopWatch.start();
postRepository.bulkInsert(posts);
stopWatch.stop();
//then
System.out.println("실행 시간 : " + stopWatch.getTotalTimeSeconds());
}
}
데이터(10,000개)를 저장하는데 걸린 시간은 1s 24ms 입니다.
벌크 쿼리를 사용하니 약 83s 더 빠르게 데이터를 저장했습니다.
벌크 쿼리 코드(Repo)
public void bulkInsert(List<Post> posts) {
String sql = String.format(
"""
insert into %s (user_id, contents, created_date, created_at)
values(:userId, :contents, :createdDate, :createdAt)
""", TABLE_NAME);
SqlParameterSource[] params = posts
.stream()
.map(BeanPropertySqlParameterSource::new)
.toArray(SqlParameterSource[]::new);
namedParameterJdbcTemplate.batchUpdate(sql,params);
}
INSERT INTO VALUES 쿼리문을 사용해서 벌크 삽입 코드를 구현했습니다.
주의할 점
application.properties에 아래와 같이 datasource.url에 rewriteBatchedStatements=true 옵션을 설정 해주어야 합니다.
적용방법은 다음과 같습니다.
jdbc:mysql:://DB주소:포트/DB이름?rewriteBatchedStatements=true
결론
많은 수의 데이터를 저장할때, Bulk insert를 사용해서 데이터를 저장하는 것이 훨씬 빠릅니다.
'성능 개선' 카테고리의 다른 글
Fan Out TimeLine on Read vs Write (4) | 2024.10.11 |
---|---|
Cursor기반 페이지네이션으로 응답 속도 개선하기 (5) | 2024.10.10 |
인덱스로 빠른 조회 만들기 (1) | 2024.10.08 |