성능 최적화(1) - N+1
2024. 2. 7. 22:01ㆍspring/JPA
N+1
지연로딩과 N+1
JPA로 애플리케이션을 개발할 때 성능상 가장 주의해야 한다.
=============================회원 1=================================
@Entity
@Getter @Setter
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
@Embedded
private Address address;
@JsonIgnore
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
=============================주문 N=================================
@Entity
@Table(name = "orders")
@SequenceGenerator(
name = "ORDER_SEQ_GENERATOR",
sequenceName = "ORDER_SEQ"
)
@Getter @Setter
public class Order {
@Id @GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "ORDER_SEQ_GENERATOR"
)
@Column(name = "order_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
...
}
지연 로딩으로 JPQL에서 쿼리를 가져오자
public List<Member> findAll() {
return em.createQuery("SELECT m FROM Member m", Member.class)
.getResultList();
}
지연 로딩이므로 데이터베이스에서 회원만 조회되므로 주문 컬렉션은 지연 로딩된다. 이후 비즈니스 로직에서 주문 컬렉션을 실제 사용할 때 지연 로딩이 발생한다.
public Member findMember(Long id) {
Member member = memberRepository.findById(id);
for (Order order : member.getOrders()) {
log.info("id = {}", order.getId());
}
return member;
}
회원(1)의 주문 컬렉션(N)을 순회하면서 각 주문 엔티티를 초기화 할 때마다 쿼리를 날리므로 N+1 문제가 발생한다.
해결책1 - 페치 조인
페치 조인은 SQL 조인을 사용해서 연관된 엔티티를 함께 조회하므로 지연로딩이 발생하지 않아 N+1이 발생하지 않는다.
select m from Member m join fetch m.orders
해결책2 - 하이버네이트 @BatchSize
@BatchSize 어노테이션을 사용하면 연관된 엔티티를 조회할 대 지정한 size만큼 SQL의 IN 절을 사용해서 조회한다.
만약 조회한 회원이 10명인데 size=5로 지정하면 2번의 SQL만 추가로 실행한다.
@BatchSize(size = 5)
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
아래 예제에서 order.getId()를 조회할 때 한번에 5개씩 IN 절을 사용해서 불러온다.
public Member findMember(Long id) {
Member member = memberRepository.findById(id);
for (Order order : member.getOrders()) {
//이때!!!
log.info("id = {}", order.getId());
}
return member;
}
'spring > JPA' 카테고리의 다른 글
성능 최적화(3) - 배치 처리 (0) | 2024.02.13 |
---|---|
성능 최적화(2) - 읽기 전용 (0) | 2024.02.13 |
JPQL(3) - 페이징, 조인 (1) | 2024.01.25 |
JPQL(2) - 프로젝션 (0) | 2024.01.24 |
JPQL(1) - 기본 문법 (0) | 2024.01.24 |