주문조회 v3 -fetch join

JIWOO YUN·2023년 9월 18일
0
post-custom-banner

DTO로 변환하지만 LAZY loding때문에 무수히 많은 쿼리가 발생하는 것을 fetch 조인을 통해서 최적화하자.

    public List<Order> findAllWithItem(){
        return em.createQuery("" +
                "select o from Order o" +
                " join fetch o.member m" +
                " join fetch o.delivery d"+
                " join fetch o.orderItems oi"+
                " join fetch oi.item i",Order.class).getResultList();
    }

OrderRepository에 fetch join 쿼리를 작성해준다. (Query dsl을 이용해서 짜는게 훨씬 좋다고 한다. -> 띄어쓰기를 통한 오류 발생이 없어지기 때문에) - > SpringBoot 3.x버전에서는 이렇게 처리해도 됨.

여기서 문제가 발생

order 가 현재 2개이고 orderItems가 현재 4개이다 -> 이럴 경우 fetch join이 발생되면 4개의 order가 발생한다.

1대 다 조인이 존재해서 데이터베이스의 row가 증가하게된다.

  • 중복된 데이터가 나오는 문제가 발생한다.
  • SpringBoot 3.x 부터는 hibernate6으로 업데이트 되면서 fetch join을 할 때 자동적으로 distinct 가 발생함.

기본 SQL에서는 distinct를 해도 데이터가 다르기 때문에 SQL 결과에서 중복제거에 실패한다.

  • 이해가 잘안되어 찾아보니 JPA 기본편에서 따로 자세히 설명해준다. 현재는 활용편을 먼저보고 기본편을 볼예정이라 아직 안봐서 따로 찾아봤다.

JPA에서 distinct를 사용하는 경우

  • JPA는 JPQL을 번역하여 distinct를 포함한 쿼리를 DB에게 전달

  • JPA 는 DB로 부터 반환된 결과에서 중복된 객체(동일한 메모리 주소)를 가지는 데이터를 제거한다.
  • JPA에서는 PK 가 똑같은 경우 -> 같은 걸로 친다.

fetch 조인으로 SQL이 1번만 실행되지만 단점으로 페이징이 불가능하다.

fetch join 과 같이 정의되기 때문에 메모리에서 페이징 처리를 한다는 경고 메시지를 날려준다.

  • 만약 데이터가 만개가 있을 경우 -> 만개를 전부 어플리케이션 메모리에 올린후 페이징을 진행해버리게 되고 거기서 메모리 초과가 발생할 수 있는 위험이 발생한다.
  • 1대다 페치 조인인 경우에서는 페이징을 하면 안된다. => 1대 다 관계에서는 데이터가 뻥튀기가 발생해서 페이징이 불가능해진다. 그외의 관계에서는 사용이 가능하다.
  • 1대다 페치조인은 1개만 사용이 가능하다. -> 둘 이상에 페치조인을 사용하게 되면 JPA에서 데이터가 부정합이 발생할 수 있다.

fetch join distinct 에 관련 설명 : https://devraphy.tistory.com/602

profile
열심히하자
post-custom-banner

0개의 댓글