-
JPA deleteByXX의 1+N 문제와 성능 저하 해결 방법Spring/JPA 2025. 3. 18. 10:29728x90반응형
JPA를 사용하면서 deleteByCouponId(Long couponId)와 같은 네이밍 메서드를 활용하면 간편하게 특정 ID를 기반으로 데이터를 삭제할 수 있지만 이러한 메서드를 사용할 때 몇 가지 주의해야 할 점이 있습니다.
deleteByCouponId의 동작 방식
JPA에서 deleteByCouponId와 같은 메서드를 실행하면 내부적으로 다음과 같은 과정을 거칩니다.
- 먼저 couponId를 기반으로 해당하는 엔티티 목록을 조회합니다.
- 조회된 엔티티들을 하나씩 순회하면서 EntityManager의 remove 메서드를 호출하여 삭제합니다.
- 삭제된 엔티티는 1개씩 flush 되며 트랜잭션이 걸려 있다면 커밋 시 최종 반영됩니다.
이 과정에서 단순히 deleteByCouponId를 호출하면 SQL의 DELETE FROM table WHERE coupon_id = ? 같은 단순한 쿼리가 실행될 것이라고 생각하기 쉽지만 실제로는 조회 후 반복문을 돌면서 삭제하는 방식으로 동작합니다.
deleteBy 메서드 사용 시 발생할 수 있는 문제
1. JPA 내부 코드
// JpaQueryExecution.class protected Object doExecute(AbstractJpaQuery jpaQuery, JpaParametersParameterAccessor accessor) { Query query = jpaQuery.createQuery(accessor); // 쿼리 제작 (조회용) List<?> resultList = query.getResultList(); // 쿼리 실행 for(Object o : resultList) { // 반복 this.em.remove(o); // 실제 삭제 (이때 @Id 삭제) } return jpaQuery.getQueryMethod().isCollectionQuery() ? resultList : resultList.size(); }2. 불필요한 조회 비용
만약 deleteByCouponId가 단순히 DELETE FROM 쿼리를 실행하는 것이 아니라면 먼저 해당하는 데이터를 조회하는 쿼리가 실행되기 때문에 데이터 양이 많을 경우 조회하는 비용이 커질 수 있습니다.
3. N+1 문제 발생 가능성
연관된 엔티티가 있는 경우 deleteByCouponId를 호출하면 연관된 엔티티들도 함께 조회될 가능성이 있습니다.
만약 Cascade 설정이 되어 있다면 삭제 시 연관 데이터를 추가적으로 조회하여 삭제하는 과정에서 N+1 문제가 발생할 수 있습니다.
4. 성능 저하 문제
조회된 데이터를 하나씩 삭제하는 방식이므로 데이터 개수가 많다면 불필요한 루프를 반복하는 문제가 발생합니다.
만약 1000개의 데이터를 삭제해야 한다면 단일 DELETE 쿼리 한 번으로 처리할 수 있는 작업을 1000번의 개별 DELETE 쿼리로 실행하게 되어 성능 저하를 유발할 수 있습니다.
해결 방법
@Modifying과 @Query를 활용한 직접 삭제
조회 없이 바로 삭제하는 방법으로는 @Modifying과 @Query를 사용하는 것이 있습니다.
@Repository public interface CouponRepository extends JpaRepository<Coupon, Long> { @Modifying @Query("DELETE FROM Coupon c WHERE c.couponId = :couponId") void deleteByCouponId(@Param("couponId") Long couponId); }이렇게 하면 조회 없이 즉시 삭제하는 DELETE FROM 쿼리가 실행되므로 성능이 향상됩니다.
- 만약 CouponId가 N개라면 IN 절을 활용해서 삭제할 수 있습니다.
[JPA] 벌크 연산(Bulk Operation) 알고 계신가요?
1. 벌크 연산 (Bulk Operation)이란?벌크 연산이란 N개의 데이터를 한 번에 UPDATE 또는 DELETE 하는 작업을 의미합니다.Spring Data JPA에서 벌크 연산을 수행하기 위해서는 @Modifying이 필요합니다.2. 왜 필요
jangto.tistory.com
728x90반응형'Spring > JPA' 카테고리의 다른 글