본문 바로가기
Spring/JPA

[SpringBoot] JPA Collection 페치 조인 최적화

by 진꿈청 2024. 1. 29.

Collection은 @ManyToOne가 아닌 @OneToMany를 사용하는 변수에 사용된다.

 

하지만,

@OneToMany. 즉, 일대다 관계에서 Collection을 조회하면 데이터가 뻥튀기가 된다.

예를 들어, Order(주문), OrderItem(주문된 아이템)이 있다고 했을 때 관계의 주인은 OrderItem이다.

 

하지만,

관계의 주인(외래키)은 N인 OrderItem이 갖고 있으므로,

Order를 기준으로 조인을 진행하면 데이터가 늘어난다.

그렇기에 반환시 중복된 데이터가 나오게 된다.

 

따라서,

기존의 페치 조인 최적화 쿼리와는 달리 jpql 혹은 querydsl에서 distinct를 추가 해주어야 한다.

    @Override
    public List<Order> findAllWithItem() {
        QOrder order = QOrder.order;
        QMember member = QMember.member;
        QDelivery delivery = QDelivery.delivery;
        QOrderItem orderItem = QOrderItem.orderItem;
        QItem item = QItem.item;

        return jpaQueryFactory
                .select(order)
                .distinct()
                .from(order)
                .join(order.member, member)
                .fetchJoin()
                .join(order.delivery, delivery)
                .fetchJoin()
                .join(order.orderItems, orderItem)
                .fetchJoin()
                .join(orderItem.item, item)
                .fetchJoin()
                .fetch();
    }

여기서 알아야 할 점은 해당 querydsl 또는 jpql를 토대로 생성된 Query를 DBMS에 그대로 입력하면 뻥튀기 된 데이터가 나온다.

이는 DB가 아닌 JPA에서 객체가 같다면 알아서 제거하여 준다는 것을 기억하자.

 

 

생성된 쿼리에 대한 DB의 결과

 

 

Collection 페치 조인의 문제점

하지만, Collection 페치 조인을 하면 2가지의 문제점이 존재한다.

 

1. 페이징이 어렵다

DB 입장에서는 뻥튀기 된 데이터를 갖고 있기 때문에 limit을 설정하기가 애매하다.

따라서, 만약 Collection 페치 조인에서 페이징 작업을 하게 되면 메모리에서 페이징 작업을 처리한다.

만약, 페이징 데이터가 굉장히 많다면 큰 문제로 다가올 것이다.

(하지만, 위 문제는 해결 가능하다는데 다음 게시물에서 다루겠다.)

 

2. Collection 페치 조인은 1개만 사용할 수 있다.

계속 언급하였지만, DB에서 데이터가 뻥튀기 되기 때문에 여러 Collection 페치 조인을 사용하면,

DB 입장에서 데이터가 너무 늘어날 뿐더러 어느 것을 기준으로 처리해야 할지 추론하는 것이 어려워진다.

따라서, 페치 조인은 1개만 사용 가능하다.

 

 

본 내용은 김영한 강사님의 인프런 JPA 강의를 토대로 작성되었습니다.