JPA를 사용해서 개인프로젝트를 진행하면서 발생한 N+1문제와 이를 해결하면서 겪은 오류에 대해 정리해보려고합니다. 간단한 오류해결 문제만 정리를 하려고 하니 이론에 대해 자세히 알고싶으신 분들은 이 링크(아직작성되지않음)를 먼저 읽고 오시면 좋을것 같습니다.
JPA를 사용하는 경우 xxxToOne같은 어노테이션으로 엔티티 관계가 형성되어 있을때 불필요한 쿼리가 더 수행되는 경우가 발생합니다.
public class PostEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private UserEntity user;
}
만약 전체 글 목록을 출력하고 싶어 JPA의 findAll
메소드를 사용하여 Post를 조회하게 된다면, Post 엔티티 별로 각각 User 엔티티를 또 조회하게 됩니다.
여기서 만약 ? 작성된 글이 5개라면 Post를 조회하는 쿼리와 각각 Post 엔티티에 해당하는 User 엔티티를 조회하기 때문에 추가로 5개의 쿼리가 수행이 됩니다.
해당 문제는 join fetch 키워드를 사용하여 해당 문제를 해결할 수 있습니다.
@Query("select p from PostEntity p join fetch p.user")
Page<PostEntity> findAllJoinFetch(Pageable pageable);
위 처럼 페이징을 위한 쿼리로 fetch 조인을 사용하게 되면 CountQuery를 정상적으로 만들어주지 못하기 때문에 아래와 같은 오류가 발생합니다.
Reason: Count query validation failed for method public abstract org.springframework.data.domain.Page com.couple.sns.domain.post.persistance.repository.PostRepository.findAllJoinFetch(org.springframework.data.domain.Pageable)
페이징 처리를 위해 전체 카운터를 처리하는 countQuery가 작성되어있지않으면 JPA에서 임의로 원본 쿼리를 보고 countQuery를 생성을 합니다. fetch 조인을 사용하게 되면 해당 부분에 대한 오류가 발생하기 때문에 countQuery를 분리해서 사용해야한다고 합니다.