API 개발 고급 - 컬렉션 조회 최적화 2
1. v3 엔티티를 DTO로 변환 - 페치 조인 최적화
1
2
3
4
5
6
7
8
9
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();
}
레포지토리단에 fetch join을 이용해 orderItem 을 가져와보자.
근데 이렇게 하면 order 1개에 orderItem은 여러 개이기 때문에, order를 조회하면 orderItem 갯수 만큼 조회 컬럼이 뻥튀기 될 수 밖에 없다..
Hibernate 6.0부터는 HQL(JPQL의 구현체)에 DISTINCT가 자동 적용된다.
쿼리로 조회하면 4개 나오는데.. 알아서 distinct 해준다..
근데 DB에선 distinct 가 아예 컬럼이 중복이 돼야 제거가 되는데.. 내 생각엔 객체 입장에선 객체 안에 객체를 들고 있어서 하나를 제거해도 문제가 없는 것 같다.
아무튼 쿼리 12 번에서 1번으로 줄어들었다..
컨트롤러나 DTO 수정이 없이 레포지토리 수정 만으로 엄청나게 성능 튜닝 되는 것이 너무 신기하다.
- 페치 조인으로 SQL이 1번만 실행 됨.
-
distinct를 사용한 이유는 1대다 조인이 있으므로 데이터베이스 row가 증가한다. 그 결과 같은 order 엔티티 의 조회 수도 증가하게 된다. JPA의 distinct는 SQL에 distinct를 추가하고, 더해서 같은 엔티티가 조회 되면, 애플리케이션에서 중복을 걸러준다. 이 예에서 order가 컬렉션 페치 조인 때문에 중복 조회 되는 것을 막아준다. - 단점 : 페이징 불가능
[!NOTE] Content1 대 다 페치 조인을 한 순간 order의 개수는 정확히 알 수 없다. 이로 인해 JPA에서는 일단 모든 데이터를 메모리에 올려버리고 그 안에서 sorting 한다. → 데이터 몇 만개 라고 생각하면..
참고 : 컬렉션 페치 조인을 사용하면 페이징이 불가능하다. 하이버네이트는 경고 로그를 남기면서 모든 데이터를 DB에서 읽어오고, 메모리에서 페이징 해버린다. (매우 위험하다.) 자세한 내용은 자바 ORM 표준 JPA 프로그래밍의 페치 조인 부분을 참고하자.
참고 : 컬렉션 페치 조인은 1개만 사용할 수 있다. 컬렉션 둘 이상에 페치 조인을 사용하면 안된다. 데이터가 부정합 하게 조회 될 수 있다.
댓글남기기