일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- java set 출력
- 항해15기
- 프로그래머스제일작은수
- 격파르타비전공자
- java참조자료형
- java최솟값구하기
- java set 저장
- java알고리즘
- java 자료구조 활용
- 격파르타후기
- 작은수제거하기
- 비전공자sqld
- java기본자료형
- javaJRE
- java알고리즘문제풀이
- 코딩부트캠프후기
- java list 출력
- 항해99후기
- sqld자격증합격
- java list 저장
- 컴파일
- java map 출력
- 격파르타합격후기
- 프로그래머스
- 격파르타장점
- java map 저장
- 노베이스부트캠프
- 인터프린터언어
- java map
- javaJVM
- Today
- Total
코딩과 결혼합니다
[JPA] 지연 로딩과 조회 성능 최적화(2) 본문
https://coding-s2-chaewon.tistory.com/252
[JPA] 지연 로딩과 조회 성능 최적화(1)
등록이나 수정 등은 데이터 한 건을 다루는 것이기 때문에 거의 성능 문제가 발생하지 않는다. 주로 조회하는 데에 문제가 발생하는데 이번에는 여러 방법으로 데이터를 조회해 보면서 JPA로 성
coding-s2-chaewon.tistory.com
@GetMapping("/api/v2/simple-orders")
public List<SimpleOrderDto> ordersV2(){
return orderRepository.findAllByString(new OrderSearch()).stream()
.map(SimpleOrderDto::new)
.collect(toList());
}
Entity를 조회해서 Dto로 변환하는 방법이다.
N+1 문제
위의 방법은 N+1 문제를 일으킨다.
N+1 문제란 쿼리가 1 + N 만큼 실행되는 것이다.
내 코드에서는 order가 총 2(N) 개이며 쿼리가 1+ N + N번 실행된다. [1 + 2 + 2 = 5]
@Data
static class SimpleOrderDto {
private Long orderId;
private String name;
private LocalDateTime orderDate;
private OrderStatus orderStatus;
private Address address; //배송지 정보
public SimpleOrderDto(Order order) {
orderId = order.getId();
name = order.getMember().getName();
orderDate = order.getOrderDate();
orderStatus = order.getStatus();
address = order.getDelivery().getAddress();
}
}
- 처음 1은 order 조회(order 조회 결과 수가 N이 된다.)
- order에서 member로 가며 지연로딩 조회 2(N) 번
- order에서 dlivery로 가며 지연로딩 조회 2(N) 번
만약 주문한 user가 같은 사람이라면 지연로딩은 영속성 컨텍스트에서 조회하므로, 이미 조회된 경우에는 쿼리를 생략한다. 하지만 대부분의 경우 다른 user가 주문한 것을 조회할 것이고, 만일 order의 결과가 2개 이상이라면 더욱 많은 쿼리가 나가게 될 것이다.
🤔 원래대로라면 쿼리가 5개가 나가는 게 맞지만 나는 계속해서 7개의 쿼리가 나온다.
나와 같은 사례를 찾았다.
학습 페이지
www.inflearn.com
이유 : 하이버네이트 6 버전 OneToOne 관계 버그
- 하이버네이트 5 까지는 정상 작동하고 해당 쿼리도 추가로 호출되지 않는다.
- 최신버전에서 OneToOne 관계일 때 발생하는 버그로 추측. 하이버네이트 6이 나오면서 내부 엔진이 많이 개선되었는데, 그러면서 연관관계가 복잡한 경우에 아직 해결이 안 되는 것 같다는 김영한 개발자님의 답이었다.
- 문제가 해결되기 전까지는 OneToOne 관계에서 최적화가 필요한 경우 fetch join을 적극적으로 사용하자!
@GetMapping("/api/v3/simple-orders")
public List<SimpleOrderDto> ordersV3(){
return orderRepository.findAllWithMemberDelivery().stream()
.map(SimpleOrderDto::new)
.collect(toList());
}
위와 매우 유사한데 여기서는 fetch join을 사용해 주었다.
OrderRepository에 아래의 코드를 추가해 주었다.
public List<Order> findAllWithMemberDelivery() {
return em.createQuery(
"select o from Order o" +
" join fetch o.member m" +
" join fetch o.delivery d", Order.class)
.getResultList();
}
이를 사용하여 쿼리 1번에 조회가 가능하다.
select
o1_0.order_id,
d1_0.delivery_id,
d1_0.city,
d1_0.street,
d1_0.zipcode,
d1_0.status,
m1_0.member_id,
m1_0.city,
m1_0.street,
m1_0.zipcode,
m1_0.name,
o1_0.order_date,
o1_0.status
from
orders o1_0
join
member m1_0
on m1_0.member_id=o1_0.member_id
join
delivery d1_0
on d1_0.delivery_id=o1_0.delivery_id
- order와 member조인 - order와 delivery 조인
- 이렇게 조인한 것을 하나의 select 절에 풀어서 반환한다.
- 페치 조인으로 order, member, delivery는 이미 조회된 상태 이므로 지연로딩에 대해 고민하지 않아도 된다.
'2세 > JPA' 카테고리의 다른 글
[JPA] 프록시 - 즉시 로딩과 지연 로딩 (0) | 2024.02.22 |
---|---|
[JPA] 프록시 (0) | 2024.02.21 |
[JPA] 지연 로딩과 조회 성능 최적화(1) (0) | 2024.02.19 |
[JPA] API 설계 시 주의할 점(DTO 사용하기) (0) | 2024.02.17 |
[JPA] 아키텍처 패턴(+ 디자인 패턴) (0) | 2024.02.15 |