✔ 성능 최적화

1. N+1 문제

JPA로 애플리케이션을 개발할 때 성능상 가장 주의해야 하는 것이 N+1 문제다.

@Enttiypublic class Member{    @Id @GeneratedValue    private Long id;    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)    private List<Order> orders = new ArrayList<Order>();    ...}
@Entity@Table(name = "ORDERS")public class Order{    @Id @GeneratedValue    private Long id;    @ManyToOne    private Member member;    ...}

회원과 주문정보는 1:N, N:1 양방향 연관관계.

회원이 참조하는 주문정보(Member.orders)를 즉시 로딩으로 설정.

즉시 로딩과 N+1

특정 회원 하나를 em.find()로 조회하면 즉시 로딩으로 설정한 주문정보도 함께 조회한다.

em.find(Member.class, id);--실행된 SQLSELECT M.*, O.*FROM Member m OUTER JOIN ORDERS OON M.ID = O.MEMBER_ID

SQL을 두 번 실행하는 것이 아니라 조인을 이용해 SQL을 한 번의 SQL로 회원과 주문정보를 함께 조회한다.

여기까지만 보면 즉시 로딩이 상당히 좋아보인다.

문제는 JPQL을 사용할 때 발생하는데

String jpql = "SELECT m FROM Member m";List<Membe> members = em.createQuery(jpql, Member.class).getResultList();

JPQL을 실행하면 JPA는 분석 후 SQL을 생성한다.

이때는 즉시 로딩과 지연 로딩에 대해 전혀 신경쓰지 않고 JPQL만 사용해서 SQL을 생성한다.

SELECT * FROM MEMBER

SQL의 실행 결과로 먼저 회원 엔티티를 애플리케이션에 로딩한다.

회원 엔티티와 연관된 주문 컬렉션이 즉시 로딩으로 설정되어 있어 JPA가 주문 컬렉션을 즉시 로딩하려고 다음 SQL을 추가로 실행한다.