N+1 문제를 해결하기 위한 방법으로 대부분 fetch join을 언급합니다. 하지만 fetch join만이 유일한 해결책은 아닙니다. 저는 QueryDSL의 Projections을 활용한 DTO 직접 조회 방식으로 N+1 문제를 해결해보았습니다.
기존 fetch join 방식은 엔티티의 모든 정보를 가져오고, 추후 DTO로 변환하는 과정이 필요했습니다. 반면 Projections을 활용하면:
- 필요한 컬럼만 선택적으로 조회 가능
- 연관 관계에서 발생하는 추가 쿼리 방지
- fetch join 없이도 효율적인 쿼리 실행
- 엔티티에서 DTO로의 변환 과정 생략
@Override public List<FindHospitalReservationDto> findHospitalReservationByUserId(Long userId) { return jpaQueryFactory .select(Projections.constructor(FindHospitalReservationDto.class, hospitalReservationEntity.hospReservationId, hospitalReservationEntity.reservationAt, hospitalReservationEntity.reservationTime, hospitalReservationEntity.user.socialUserId, hospitalReservationEntity.hospital.hospId, hospitalReservationEntity.hospital.yadmNm, hospitalReservationEntity.hospital.addr, hospitalReservationEntity.hospital.telno )) .from(hospitalReservationEntity) .leftJoin(hospitalReservationEntity.user, socialUserEntity) .leftJoin(hospitalReservationEntity.hospital, hospitalEntity) .where(hospitalReservationEntity.user.socialUserId.eq(userId)) .fetch(); }
코드 설명
DTO 직접 조회
- Projections.constructor를 사용하여 DTO로 직접 조회
- 필요한 컬럼만 선택적으로 지정
- 엔티티 변환 과정 없이 바로 DTO 반환
조인 처리
- 필요한 테이블과 leftJoin으로 연결
- fetchJoin이 필요 없음 (DTO로 직접 조회하기 때문)
- 연관된 엔티티의 특정 컬럼만 선택적으로 조회
쿼리 실행
- 단일 쿼리로 모든 데이터 조회
- N+1 문제 해결
- 불필요한 데이터 조회 방지
N+1 문제를 해결하기 위해 일반적으로 사용하는 fetch join 외에도 QueryDSL의 Projections을 활용한 방식이 효과적인 해결책이 될 수 있습니다. 이 방식은 필요한 데이터만 조회하고 DTO로 직접 변환함으로써 성능상의 이점을 제공할 뿐만 아니라, 코드도 더 간결해집니다.
더 나아가 이러한 접근은 단순히 N+1 문제 해결을 넘어서, 상황에 따라 적절한 기술을 선택하고 적용하는 것의 중요성을 보여줍니다. fetch join이 항상 최선의 해결책은 아니며, 때로는 다른 접근 방식이 더 효율적일 수 있다는 것을 배웠습니다.