실전! 스프링 부트와 JPA 활용2(API 개발과 성능 최적화)

Ch04. API 개발 고급(컬렉션 조회 최적화) - 주문 조회 V3(Entity -> DTO로 변환 ( 페치 조인 최적화))

webmaster 2021. 12. 21. 10:54
728x90

데이터 뻥튀기

쿼리
일대다 조인을 하게 되면 다쪽으로 데이터가 뻥튀기 되는 문제가 발생한다.

  • 관계형 데이터 베이스는 조인을 하게 되면 주문 아이템이 2개이기 때문에 데이터가 2개가 출력이 된다.

JPA 에서 일대다 조인 데이터 뻥튀기 문제 해결하기

JQPL 을 페치조인으로 가지고 오게 되면 데이터가 뻥튀기가 되버린다.
주소값을 찍어도 같은 데이터끼리는 같다.
같은 객체를 참조중인것을 알 수가 있다.
2가지 일을 해준다.

  • distinct로 해결
    • SQL Distinct를 해준다.
    • 단 이경우에는, 데이터가 동일해야지 중복을 제거해 주지만 join을 해서 출력되는 데이터는 다르기 때문에 dinstinct가 되지 않는다.
  • 애플리케이션에 데이터를 가지고 와서 JPA가 알아서 중복을 제거해 준다
    • JPA에서 Root Entity을 중복을 제거해준다.

정리

  • 페치 조인으로 SQL이 1번만 실행됨
  • distinct를 사용한 이유는 1대다 조인이 있으므로 데이터베이스 row가 증가한다. 그 결과 같은 order 엔티티의 조회 수도 증가하게 된다. JPA의 distinct는 SQL에 distinct를 추가하고, 더해서 같은 엔티티가 조회되면, 애플리케이션에서 중복을 걸러준다. 이 예에서 order가 컬렉션 페치 조인 때문에 중복 조회되는 것을 막아준다.

단점

페이징시 해당 에러를 출력하면 어플리케이션내에서 페이징을 시도한다.

  • 페이징 불가능
  • 하이버네이트가 경고 오류를 낸다.
  • 하이버네이트가 fetchJoin을 하였는데 페이징 쿼리를 사용해서 메모리에서 sorting 한다는 뜻이다.
    • 잘못하면 메모리에 초과 에러가 발생할 수도 있다.
  • 이런 현상이 발생하는 이유?
    • 일대다 조인을 하는 순간 order을 기준 자체가 다 틀어지기 때문에 페이지를 할 수가 없다.
    • 컬렉션 페치 조인을 사용하면 페이징이 불가능하다. 하이버네이트는 경고 로그를 남기면서 모든 데이터를 DB에서 읽어오고, 메모리에서 페이징 해버린다(매우 위험하다). 자세한 내용은 자바 ORM 표준 JPA 프로그래밍의 페치 조인 부분을 참고하자.
  • 컬렉션 페치 조인은 1개만 사용할 수 있다. 컬렉션 둘 이상에 페치 조인을 사용하면 안 된다. 데이터가 부정합 하게 조회될 수 있다.

 

728x90