1. 1:N fetch join의 문제점
1:N 에서 join을 하면 N 개의 row 가 나오는 문제점이 있다.
- orders(1) : order_item(n) 의 연관관계의 경우 조인하면 아래와같이 로우가 4개 생긴다.
위의 조인된 컬럼에서 중복을 제거하고 싶다.. 어떻게?
- JPA의 distinct 를 사용해서 제거한다.
- DB에 distinct 키워드 제공
- 엔티티가 중복인 경우, 중복을 제거해서 컬렉션에 담아주는 기능을 제공한다.
em.createQuery(
"select distinct o from Order o" +
" join fetch o.orderItems oi" +
" join fetch oi.item i", Order.class).getResultList();
단점
- 1:N fetch join 에서는 페이징이 불가능하다.
- 1:N fetch join 은 한개만 사용(1:N:M 불가) 할 수 있다.
2. 페이징, 한계 돌파
- ToOne 관계는 모두 fetch join 을 한다.
- 컬렉션은 fetch join 이 아닌 Lazy Loading 으로 조회한다.
- Lazy Loading 을 최적화 하기위해 (Lazy Loading 을 In query로 최적화)
- spring.jpa.properties.default_batch_fetch_size (글로벌 설정)
- @BatchSize (개별 설정)
@BatchSize 적용방법
- 컬렉션(@XToMany)에 적용하는 경우 (프로퍼티에 적는다.)
@BatchSize(size = 1000)
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
- XToOne 에 적용하는 경우 (엔티티에 직접 적는다.)
@BatchSize(size = 100)
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
@Getter @Setter
public abstract class Item {
장점
- 쿼리 호출수 1+N => 1+1
- 컬렉션 fetch join 에서 불가능했던 paging 이 가능해짐
default_batch_fetch_size 는 몇개로?
- 100 ~ 1000 사이를 선택하자
- IN query를 사용하는데, DB 에서 IN 파라미터를 제한하기도 하기 때문에 데이터베이스 환경에 대한 확인이 필요
- 사이즈를 크게하면 순간적인 부하가 DB, 어플리케이션에 증가하기 때문에 이를 고려해야 한다.
3. DTO 조회 컬렉션조회에서 최적화
방법
- Dto 리스트로 받는 쿼리를 작성 (in 절 사용)
- 받은 뒤, Map<Id, List<>> 으로 변환
- 루프를 돌면서 set
List<OrderItemQueryDto> orderItems = em.createQuery(
"select new jpabook.jpashop.repository.order.query.OrderItemQueryDto(oi.order.id, i.name, oi.orderPrice, oi.count)" +
" from OrderItem oi" +
" join oi.item i" +
" where oi.order.id in :orderIds", OrderItemQueryDto.class)
.setParameter("orderIds", orderIds)
'강의 정리 > 스프링 부트와 JPA활용 2' 카테고리의 다른 글
3. OSIV와 성능 최적화 (0) | 2021.01.09 |
---|---|
1. 지연 로딩과 조회 성능 최적화 (0) | 2021.01.07 |