본문 바로가기
카테고리 없음

[Spring] JPA save(), saveAll(), deleteAll(), deleteAllInBatch(), @Query 비교

by 잉ㅈI 2024. 11. 10.

01. 들어가기전

프로젝트를 하면서, 엔티티의 갯수가 많아지고, 여러 부분을 저장하거나 삭제하는 로직을 구현하는데!

이때 여러 jpa 쿼리메소드가 성능차이가 나는건 알고있었지만, 이유를 정확하게 몰랐다! 까보면서 알아보쟈 !

02.save()

03.saveAll()

  • 둘다 @Transactional 적용되어있음
  • save(): 1건 마다 save()함수 호출
  • saveAll(): 1건 마다 인스턴스 내부의 save()함수 호출

→ saveAll()이 성능이 더 좋은데, 이유가 뭐냐?

  • @Transactional
    • AOP 프록시 기반으로 외부 Bean 객체가 있고, 이 객체의 함수를 호출해 Intercept가 되어 트랜잭션으로 묶이게 됨
    • Bean 객체 내부에서 내부함수 호출 시 @Transcational 적용X
  • save() 호출 시,
    • 상위 @Transactional 존재하는 경우, 해당 Transcation에 참여
    • 존재하지 않은 경우, 새로 Trascation을 생성 후 save 후 commit
    • 외부 빈(repository) 객체의 save 함수 호출
      • 갯수가 많아질수록 비용발생 + 시간 오래걸림
  • saveAll() 호출 시,
    • Bean 객체의 내부함수를 호출하기 때문에 save() 호출마다 Transaction이 생성되거나 참여하는 프록시 로직을 타지않고, 단순 메서드 호출
      • 비용 발생 안함

→ 결론?

출처: https://velog.io/@msung99

  • save(): 300개 데이터 insert시, 트랜잭션 300번 발동
  • saveAll(): 300개의 묶음 단위 하나의 트랜잭션 발동

04.deleteAll()

  • deleteAll() 까보면 while문으로 delete쿼리가 나가기 때문에 사실 delete 쿼리가 하나씩 나감!
  • 결국 데이터가 1000개면 1000번, 10000개면 10000번 돈다는 것이다

05. deleteAllInBatch()

  • "QueryUtils.getQueryString("delete from %s x" 부분이 있는데,
    • 즉, delete from {테이블 이름} 으로 delete 쿼리만 수행!
    • findAll이나 findById를 사용하지 않았기 때문에 delete이전에 select하는 과정은 없음
    • 벌크 작업으로 처리
  • 대용량일 수록 성능 좋음
  • 벌크(Bulk): 한 번의 쿼리로 다수의 데이터를 처리하는 방식
  • 배치(Batch): 데이터를 여러 번에 나누어 처리하는 방식
  • 벌크: 배치처리보다 빠르고 인덱스 활용할 수 있는 장점
    • 전이 메커니즘(cascadeType.ALL)이나 자동 애플리케이션 수준 낙관적 잠금 메커니즘(@Version)의 장점X
    • 엔티티 수정 사항이 영속성 컨텍스트에 자동으로 반영되지 않음
      • 예시)@Version 필드 가진 엔티티에서 삭제 진행시, 엔티티 버전 정보가 업데이트 되지 않음
      • 다른 트랜잭션에서 이 엔티티 참조하고 있을 시, 낙관적 잠금 충돌 감지 못함

07. @Query 사용하기

  • 이때 사실 deleteAllInBatch에서 applyAndBind를 까보면 !! or 연산이 들어가고있었다!

  • 그렇다면 or 대신 in 절을 사용하려면 어떻게 해야하는지! -> @Query를 직접 사용하면된다!
@Modifying
@Query("delete from CommentCard cc WHERE cc.writer.pk = :memberPk")
void deleteCommentCardByMemberPk(@Param("memberPk") Long memberPk);
  • 직접 쿼리를 작성하면 or대신 in 절을 사용하여 한번에 날릴수 있음
  • in절을 사용하면 or을 연속해서 사용하는 것 보다 속도가 훨씬 빠르다!
    • or절: ALL, in절: range를 거침.

 

 

<참고>

https://haon.blog/haon/jpa/bulk-insert/

https://maivve.tistory.com/342

https://haon.blog/haon/jpa/bulk-insert/

https://00h0.tistory.com/97

https://velog.io/@msung99