기존에 delete query를 jpa에서 제공하는 메소드 그대로 사용했었다.
groupMemberRepository.deleteByStudyGroup(group);
그런데 발생하는 delete 쿼리가 한 개가 아니었다.
실제로 4개의 GroupMember 엔티티를 위 메소드로 삭제하면 아래처럼 쿼리가 발생한다.
Hibernate:
delete
from
group_member
where
id=?
Hibernate:
delete
from
group_member
where
id=?
Hibernate:
delete
from
group_member
where
id=?
Hibernate:
delete
from
group_member
where
id=?
deleteBy-
로 시작하는 메소드를 사용해 데이터를 삭제하면 건수에 상관 없이 먼저 select로 조회한 후에 이에 대한 결과를 한 건씩 삭제한다.
N개의 레코드를 지운다면 N번의 delete 쿼리가 발생한다는 것이다. 지금은 엔티티 수가 많이 없으니 문제가 안되겠지만, 쿼리 수가 많은 건 디스크 I/O, 네트워크 오버헤드 등 성능 저하의 원인이 될 수 있다. 그래서 이를 해결할 수 있는 대안들을 실험해보았다.
groupMemberRepository.deleteAll(groupMemberRepository.findAllByStudyGroup(studyGroup));
GroupMemberRepository
에 해당 유저들이 존재하는지 먼저 select로 확인한 후, 이를 List<>로 만들어 deleteAll
에 넣어보았다.
Hibernate:
select
gm1_0.id,
gm1_0.is_visible,
gm1_0.join_date,
gm1_0.role,
gm1_0.study_group_id,
gm1_0.user_id
from
group_member gm1_0
where
gm1_0.study_group_id=?
Hibernate:
delete
from
group_member
where
id=?
Hibernate:
delete
from
group_member
where
id=?
Hibernate:
delete
from
group_member
where
id=?
Hibernate:
delete
from
group_member
where
id=?
하지만 여전히 delete query는 4번 나갔다. 게다가 파라미터로 입력 받은 GroupMember 리스트를 조회하는 메소드 때문에 select 쿼리도 한 번 수행하게 된다. deleteBy-
보다 더 비효율 적인 것이다.
deleteAll()
메소드 또한 리스트 하나하나에 대해 해당 id가 존재하는지 검사하며 delete를 진행한다. id 개수만큼 for문을 돌리게 되는 것이다. 이는 deleteBy-
만큼이나 성능 저하의 원인이 되므로 사용하지 않는다.
이번에는 Spring Data JPA에 있는 deleteAllInBatch()
메소드를 사용해봤다. 한 번의 쿼리로 데이터들을 삭제할 수 있다.
groupMemberRepository.deleteAllInBatch(groupMemberRepository.findAllByStudyGroup(studyGroup));
Hibernate:
select
gm1_0.id,
gm1_0.is_visible,
gm1_0.join_date,
gm1_0.role,
gm1_0.study_group_id,
gm1_0.user_id
from
group_member gm1_0
where
gm1_0.study_group_id=?
Hibernate:
delete gm1_0
from
group_member gm1_0
where
gm1_0.id=?
or gm1_0.id=?
or gm1_0.id=?
or gm1_0.id=?
batch query라 확실하게 많이 줄었다. 처음 select문으로 delete 할 GroupMember 레코드들을 조회하고, 해당 쿼리로 받아온 엔티티들을 batch delete로 제거한다. deleteAll
보단 deleteAllInBatch
를 사용하는 게 확실히 나은 것 같다.
이번엔 where 절을 직접 작성해보기로 한다.
@Modifying
@Query("delete from GroupMember gm where gm.studyGroup = :studyGroup")
void deleteAllByStudyGroup(StudyGroup studyGroup);
Hibernate:
delete gm1_0
from
group_member gm1_0
where
gm1_0.study_group_id=?
@Query
작성한 그대로 수행한다. 사실 가장 좋은 방법이다. 웬만하면 조건부로 데이터를 삭제해야할 땐 직접 쿼리를 작성하는 방법으로 진행하자.
참고
https://monsters-dev.tistory.com/88
https://jojoldu.tistory.com/235
https://frogand.tistory.com/172