회사에서 개발하는 주요 프로젝트는 웹 개발로, B2B 모델이다.
트래픽이 적은 대신, 초 대용량의 데이터가 담겨 있는데, 이러한 데이터를 어떻게 처리하면 좋을지 쿼리 관점에서만 블로그를 작성해 볼 예정이다.
회사 코드는 보안 사항으로, 비슷한 데이터를 만들어서 예제를 작성해 보자.
엔터티/테이블은 아래처럼 되어있다.
한 개의 parents에 1만 개의 데이터들이 존재한다 가정하자.
SELECT에서 IN절 사용하기
parent id들이 담긴 리스트를 메모리 상에 가지고 있다고 할 때, 이것들로 평범하게 data들을 조회하려고 하면 총 11번의 select쿼리가 나가게 된다. (parent 10개 조회 + data 1만개씩 10번 조회)
이걸 한 번에 처리하려면 in절 select를 해야 한다. 이 부분에 대해서 코드를 작성해보자.
이처럼 in절을 잘 활용하면 벌크처리로 select할 수 있다.
이를 활용해서 batch delete도 한번 수행해보자.
한꺼번에 DELETE하기
먼저 벌크처리로 delete하지 않는 방법을 수행해보자.
놀랍게도 intelliJ에서 벌크로 처리할 수 있다고 노란줄이 나타난다. 하지만 이대로 실행해보자.
10만개의 쿼리가 추가로 나타난다. 실행 시간도 무려 17초 가까이 나타난다. 이렇게 하면 안된다는 것을 직감적으로 알아차릴 수 있다.
그러면 인텔리제이가 추천하는 벌크 방식으로 코드를 바꿔보자.
deleteAll이라는 메서드로 변경이 되었다. 수행해보면 똑같이 delete쿼리가 10만번 수행되는데, 왜 그럴까?
deleteAll이 정의된 곳을 보면, delete를 하나하나 수행하는것을 볼 수 있다.
delete가 정의된 곳을 들어가보면
결국 em의 remove를 끄집어 온다.. 이건 벌크처리가 아니다. 그러면 어떤 것을 사용해야 할까?
deleteAllInBatch를 사용하자
SimpleJpaRepository에 정의되어있는 deleteAllInBatch를 사용하면 된다.
deleteAllInBatch의 내부 동작을 정의부분부터 분석해 보자.
내부적으로 리스트를 받아와서, 1개가 아니라 여러개가 있을 때 applyAndBind 메서드를 호출하는 것을 볼 수 있다.
applyAndBind 메서드를 들어가보면
or 절로 하나하나 추가해주는 것을 볼 수 있다.
아래와 같이 테스트를 만들고 수행해보자.
이렇게되면 쿼리 한방으로 delete할 수는 있겠지만..
StackOverFlowError가 발생한다.
deleteAllInBatch에서 StackOverFlowError가 발생하는 이유는 아래 게시물에서 확인할 수 있었다.
https://blog.csdn.net/mr_wanter/article/details/114881239
Spring JPA deleteInBatch导致StackOverflow_spring data jpa的deleteinbatch栈溢出-CSDN博客
前言 数据库日志库定时清理日志数据,几天之后发现,jvm内存溢出现象。 一、问题定位 1、日志数据量太大(近40w数据) 2、源码分析 @Scheduled(cron = "0 0 1 * * ?") public void timedPullNewInfo() { Date date=ne
blog.csdn.net
deleteAllInBatch로 대용량의 데이터를 처리할 때 메모리 문제는 불가피하다고 한다..
해결책으로는 작은 배치로 데이터를 삭제하거나, 네이티브 SQL 쿼리를 사용하는 방법을 제안하고 있다.
네이티브 SQL을 사용하면 더 빠르고 메모리 문제를 피할 수 있다고 하는데, JPQL로 한번 시도해 보자.
deleteAllInBatch를 사용했을 때 세로로 or절이 쭉 이어지는 형태로 쿼리가 날아가는데 이 방식도 마음에 안들기는 했다.
그러면 이제 JPQL로 쿼리를 만들어 보자.
수행해보니 또 에러가 나타났다.
in절의 파라미터가 10만개라서 조회가 안된다고 한다. (65535개의 파라미터가 최대치)
그러면 어떻게 해야 할까... 고민을 하던 중 select처럼 parentId로 조회하면 되겠다고 생각이 들었다.
쿼리가 매우 깔끔해졌다.
수행시간 차이도 어메이징 하다.
이처럼 대용량의 데이터를 관리할 때 적절하게 사용할 수 있는 쿼리들이 있다.
앞으로도 공부해야 할 것들이 산더미다.. 까먹지 않게 잘 숙지하고 있어야 겠다.
'DEV > 개발일기 || 트러블슈팅' 카테고리의 다른 글
Coroutine과 ReactiveMongo 다중DB 환경에서 @Transactional을 사용해 보자 (0) | 2025.03.10 |
---|---|
데이터 압축을 위한 Gorilla 알고리즘 적용 사례: 사내 솔루션 개발기 및 회고 (5) | 2024.09.03 |
공유 자원에서의 동시성 이슈는 어떻게 해결해야 할까? (0) | 2023.12.15 |
pg의 멀티테넌시(스키마) 환경에서 스프링 배치를 어떻게 사용해야 할까? (0) | 2023.12.15 |