프로젝트 중 느낀 JPQL Fetch Join의 필요성

wannabeking·2022년 6월 27일
0

회고

목록 보기
2/18

프로젝트에서 헤어샵과 날짜별로 예약 가능 시간들을 포함한 디자이너 리스트를 출력하는 기능이 필요했다.

디자이너와 예약이 일 대 다 관계이고 lazy fetch type을 사용하였으며, request와 response는 다음과 같다.

@Getter
@AllArgsConstructor
@Builder
public class ReservationTimeRequestDto {

    @NotNull(message = "날짜를 입력해주세요.")
    private LocalDate date;

    @NotBlank(message = "예약 시작 시간을 입력해주세요.")
    @Pattern(regexp = "^([01][0-9]|2[0-3]):([0-5][0-9])$", message = "예약 시작 시간을 HH:mm 으로 입력해주세요.")
    private String reservationStartTime;

    @NotBlank(message = "예약 마감 시간을 입력해주세요.")
    @Pattern(regexp = "^([01][0-9]|2[0-3]):([0-5][0-9])$", message = "예약 마감 시간을 HH:mm 으로 입력해주세요.")
    private String reservationEndTime;
}
@AllArgsConstructor
@Builder
@Getter
public class ReservationTimeResponseDto {

	private Long designerId;

    private Position designerPosition;

    private String designerName;

    private String designerImage;

    private String designerInstruction;

    private List<String> reservationTimes;
}

일반적인 방법으로 디자이너를 조회해서 해당 디자이너가 가지고 있는 예약들을 가져온다면 다음과 같은 이슈가 발생한다.

lazy fetch type에서 조회를 수행하면 조회의 주체가 되는 엔터티만 영속성 컨테이너에 저장되며, 일 대 다 연관관계인 엔터티들은 나중에 get()을 수행할 때 마침내 영속성 컨테이너에 저장된다. 따라서 N 번의 추가 쿼리가 필요하다. eager fetch type은 조회를 수행하면 일 대 다 연관 관계 모두 영속성 컨테이너에 저장되어 한 번의 쿼리로 수행되는 것 같아 보이지만 실제로는 추가적으로 N개의 쿼리가 날라가는 N+1 문제가 발생한다.

이는 대량의 추가적인 쿼리를 요구하므로 성능 문제와 직결 된다.

따라서 한 번의 쿼리로 연관 관계 모두 영속성 컨테이너에 저장하는 방법이 필요했으며 fetch join이 그 방법이었다.



Fetch Join

추가적인 쿼리 없이 한 번의 쿼리로 inner join을 수행하여 연관 관계 모두 영속성 컨테이너에 저장하는 쿼리이다.

문법은 다음과 같다.

select t from Team t join fetch t.members

하지만 fetch join도 카테시안 곱이 발생할 수 있기 때문에, distinct를 사용하여 중복을 제거해야 한다.

또한 inner join이기 때문에 예시에서 member가 존재하지 않으면 team도 조회되지 않는다.



profile
내일은 개발왕 😎

0개의 댓글