SpringBoot+Jpa

1대 N fetch join 위험성

lby132 2022. 10. 27. 00:47
public List<Order> findAllWithItem() {
    return em.createQuery(
            "select distinct o from Order o" +
                    " join fetch o.member m" +
                    " join fetch o.delivery oi" +
                    " join fetch o.orderItems oi" +
                    " join fetch oi.item i", Order.class)
            .setFirstResult(1)
            .setMaxResults(100)
            .getResultList();
}

 

join fetch의 장점은 전에 설명했듯이 여러 join 관계에 있을때 쿼리를 여러번 호출하지 않고 한번에 모두 호출해서 최적화를 시킨다고 했었다. (Lazy로 설정된것보다 우선순위를 갖는다.)  그리고 1 대 N이 껴있으면 중복이 발생한다. 지금은 orderItems와 Order의 관계는

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();

1대 N인 상황이다. 그래서 중복이 발생하는데 distinct를 써주면 중복이 제거된다. 단. 어플리케이션에서 실행시킨 결과 값에서만 제거되고 쿼리는 그대로 중복이 되어 있다. jpa에서 distinct를 써주면  sql에 distinct를 날려주고 기준이되는 엔티티, 현재는 Order엔티티의 id의 값을 체크해서 중복을 없애준다. 즉 id값을 기준으로 중복을 없애는것이다. 그런데 db에서는 데이터의 모든 컬럼이름이 정확하게 일치해야 중복 제거가 되기때문에 db는 중복제거가 되지 않는다.

어쨋든 이 좋은 방법에도 문제가 있다. 이제 제목에 대한 얘기를 하자면 1대N의 관계가 있는 경우에는 페이징처리를 할때 fetch join은 문제가 된다. 저 쿼리가 실행되면

2022-10-27 00:37:35.649  WARN 1992 --- [nio-8080-exec-1] o.h.h.internal.ast.QueryTranslatorImpl   : HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!

 

이런 경고가 콘솔창에 뜬다. 자바 메모리 안에서 페이징을 하는것이다. 수많은 데이터를 페이징 처리하면 outofmemory가 날것이다.

jpa가 이런걸 해주는 이유는

이렇게 db에서 중복이 제거되지 않은 상태에서 페이징을 하려고 하면 당연히 원하는 값이 나올수없기 때문이다. 난 중복이 제거된 기준에서 페이징 처리를 하는건데 db는 그렇지 않기 때문에 경고를 띄워준것이다.

그래서 사용시 매우 주의 해야한다. 물론 1대N이 아니면 모두 상관없다. 현재 소스에서 1대N의 관계에 있는 orderItems를 제거하고 돌려보면 페이징처리가 경고없이 잘 된다.

 

마지막으로 컬렉션 페치 조인은 1개만 사용해야한다. 컬렉션 페치 조인이란 현재 orderItems에 걸려있는 fetch join이다.

소스에서 보듯이 orderItems는 컬렉션타입이다. 이런 컬렉션 페치 조인이 한개만 있어도 뻥튀기가 되는데 두개가 있다면 1대N에 N의 관계가 되면서 엄청난 뻥튀기가 되기 때문에 jpa가 데이터들을 어떤 기준으로 잡을지 모르는 경우가 생길수 있어 데이터가 부정합하게 조회될수 있기 때문이다. 

'SpringBoot+Jpa' 카테고리의 다른 글

casecade(영속성 전이)  (0) 2022.11.25
OSIV  (0) 2022.10.29
EntityManager의 @Autowired  (0) 2022.10.23
JPA사용시 @Transactional  (0) 2022.10.23
@PersistenceContext  (0) 2022.10.22