DevBoi

[JPA] JPA N+1 문제란? 본문

Develop/[JPA]

[JPA] JPA N+1 문제란?

HiSmith 2021. 7. 12. 21:12
반응형

JPA를 개발하면서, N+1문제에 대한 얘기가 많이나온다.

N+1이란 어떤걸까? 어떻게 해결해야할까?

 

우선 N+1 이란, 

어떤 게시물의 테이블을 POST라고 두고,

Post에 달린 댓글을 Comment라고 두자

 

한게시물에는 여러개의 댓글이 달릴것이고, 우리는 이것을 @OnetoMany로 둔다.

 

자 그러면, 페이징을 뿌릴때나, 특정조건에 Post테이블을 findAll해본다고하자

 

우선, 그전에 JPA에서는 각각의 fetch방법이 존재한다.

fetch란 뭘까? fetch란 특정 한개의 Entity 즉 테이블을 조회할때, 연관관계에 있는 객체들을 어떻게 가져올까?

라는 전략이다.

해당 전략은 크게 Eager, Lazy가 있다.

Eager은 연관관계에 있는 Entity를 모두 가져오고

Lazy는 getter로 접근할때만 가져오도록 허락한다.

 

그러면 여기에서, Post에 대해서 comments의 전략이 Eager인 경우,

해당 Post를 조회해 오면서, Post당, comments들을 다시 전부 가져온다.

즉 쿼리문이 Post개수만큼 돈다.

 

이것은 엄청난 성능낭비이다.

 

그래서 간단하게 해당 문제를 해결하기위해서는 fetch전략을 바꿔주면된다.

eager -> lazy

 

근데, 그러면 매번 이렇게 해줘야할까?

너무 귀찮잖아~

 

우선, 이게 발생하는 원인부터 알아야 한다.

Post를 조회하고, 하위Comment를 조회할때, Post에 대한 조회는 끝이나서, 

단순 where 로 한번더 도는 것이다. 즉 조회가 끝났기 때문에, Join이 불가하다

 

해결방법 1.

JPQL 패치 조인 사용해야한다. (지연로딩으로 설정해도, loop 시 다시 N+1이 발생하기 떄문에)

@Repository public interface PostRepository extends JpaRepository<Post, Long>

{

@Query("select p from Post p left join fetch p.commentList")

List<Post> findAllWithFetchJoin();

}

 

요론식으로 사용해서, Post를 가져올때, 하위 List<Comments> commentList들에 대한건,

join으로 바로 가져와서 서비스나, 메소드에서 List<Post> 로 담아준다.

 

해결방법2)

Batch Size지정 + Eager로딩

해당 컬럼위에 @BatchSize(size = 2) 로 지정하게 되면,

Post 갯수만큼 쿼리가 도는 것이 아니라, 정해진 숫자 만큼만 쿼리가 돈다.

반응형

'Develop > [JPA]' 카테고리의 다른 글

[JPA] Entity Mapping, Table Managing  (0) 2021.07.28
[JPA] JPA 영속 컨텍스트  (0) 2021.07.26
[JPA] 기초 CRUD 사용 해보자  (0) 2021.07.23
[JPA] JPA 기초 개념공부  (0) 2021.07.23
JPA란 무엇일까????  (0) 2021.06.28