JPA의 성능을 위해 가장 주의해야 하는 문제이다.
먼저, N+1 문제는 지연로딩, 즉시로딩에서 발생할 수 있다.
연관 관계를 갖는 테이블을 쿼리할때 발생하는 이슈로 연관 관계가 설정된 테이블을 조회할 경우 조회된 데이터 개수 (N) 만큼 연관관계를 조회 쿼리가 추가로 발생하게 되어 쿼리가 N+1번 실행되는 이슈
즉시로딩의 경우 Entity Manager를 통해 조회할 경우 즉시 연결 데이터를 조인해서 조회하기 때문에 N+1 문제가 발생하지 않는다. 하지만, JPQL을 사용할때 JPQL은 즉시 로딩, 지연 로딩을 고려하지 않기 때문에 문제가 발생하게 된다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
private Address address;
@OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
private List<Order> orders = new ArrayList<Order>();
...
}
List<Member> member = em.createQuery(”select m from Member m”,Member.class).getResultList();
로 조회를 시작하면
select * from member;
쿼리가 실행되고 즉시 로딩으로 인해 바로 아래의 쿼리가 실행된다.select * from orders where member_id = 1;
만약 for문으로 반복되서 호출되는 경우
select * from orders where member_id = 2;
select * from orders where member_id = 3;
select * from orders where member_id = 4;
select * from orders where member_id = 5;
select * from orders where member_id = 6;
와 같이 쿼리가 실행된다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
private Address address;
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY)
private List<Order> orders = new ArrayList<Order>();
...
}