[JPA] JPQL에서 limit 효과 구현하기

Yoon Uk·2023년 9월 17일
0

JPA

목록 보기
2/3
post-thumbnail

상황

Place(장소) entity와 PlaceImage(장소) entity가 지연 로딩(FetchType.LAZY) 되어있습니다.

  • Place
Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Place extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

	...

    @OneToMany(mappedBy = "place", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, orphanRemoval = true)
    private List<PlaceImage> images = new ArrayList<>();
  • PlaceImage
@Entity
@Table(name = "place_img")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PlaceImage extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

	...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "place_id")
    private Place place;

이 때 특정 Place를 조회할 때 Place와 연관된 PlaceImage 중 1개만 fetch join 하고싶은 상황입니다.

단순히 특정 Place에 연관된 PlaceImage 모두를 fetch join한 뒤 그 결과 중 하나를 선택해도 해결은 가능합니다.

  • 단순한 fetch join
@Query("select p
        from Place p 
        left join fetch p.images 
        where p.id = :id")
List<Place> findOneByIdFetchImage(@Param("id") Long id);

하지만 연관된 PlaceImage가 매우 많을 수도 있는 상황에서는 비효율적일 것이라 생각했습니다.

해결책

따라서 limit 1과 같은 효과를 얻기 위해 Pageable을 사용했습니다.

  • Pageable을 함께 사용한 fetch join
@Query("select p
        from Place p 
        left join fetch p.images 
        where p.id = :id")
List<Place> findOneByIdFetchImage(@Param("id") Long id, Pageable pageable);

PageRequest.of(0, 1)를 파라미터로 넘겨 offset은 0, pageSize는 1이 되어 limit 1의 효과를 볼 수 있습니다.

public List<Place> findOneByIdFetchImage(Long id) {
    return placeRepository.findOneByIdFetchImage(id, PageRequest.of(0, 1));
}
  • 결과 sql
select
    p1_0.id,
	...
    p2_0.id,
	...
from
    place p1_0 
left join
    place_img p2_0 
        on p1_0.id=p2_0.place_id 
where
    p1_0.id=? offset ? rows fetch first ? rows only

0개의 댓글