티스토리 뷰

TIL

JPA N+1 문제 해결하기

해미깨미 2021. 4. 7. 12:44

개인 프로젝트를 진행하면서 게시판을 만들던 중 N+1 문제가 발생했었다.

N+1 문제

JPA 페이징 API를 사용해서 게시글을 20개씩 가져오도록 구현했었는데 게시글과 댓글의 개수도 같이 보여지게 하기 위해서 Page에 담긴 Posts들을 Dto로 매핑하는 과정에서 N+1 문제가 발생했었다.

this.comments = entity.getComments().size()가 문제

comments 필드에 생성자로 값을 초기화 해주는데 페치 조인으로 Posts와 연관된 Comment들을 불러오지 않았기 때문에 select 쿼리문이 하나씩 추가적으로 발생했던 것이다.

 

처음 Querydsl과 페치 조인을 사용해서 문제를 해결하려고 했지만 페치 조인을 사용하면 페이징 API를 사용할 수 없다.

 

정확히는 사용할 수 없진 않은데 메모리에 매우 치명적이다.

페치 조인을 하게되면 DB에 있는 모든 Posts를 불러온 후에 메모리에서 페이징 처리를 하기 때문에 

 

이 문제를 해결하기 위해 구글링하느라 정말로 시간이 오래 걸렸지만...

생각보다 해결 방법은 간단했다.

 

@RequiredArgsConstructor
@Repository
public class PostsQueryRepository {

    private final JPAQueryFactory queryFactory;

    public Page<PostsPageResponseDto> findDynamic(PostsPageRequestDto requestDto, Pageable pageable) {
        QueryResults<PostsPageResponseDto> results = queryFactory
        
        	// Querydsl Projection을 사용해서 Dto 생성자에 comment count 값을 넣어준다.
                .select(Projections.constructor(PostsPageResponseDto.class,
                        posts,
                        comment.id.count()))
                .from(posts)
                .leftJoin(posts.comments, comment)
                .where(eqKeyword(requestDto.getTarget(), requestDto.getKeyword()))
                .groupBy(posts.id)
                .orderBy(posts.createdDate.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetchResults();

        return new PageImpl<>(results.getResults(), pageable, results.getTotal());
    }

    private BooleanExpression eqKeyword(SearchType searchType, String keyword) {
        if (!StringUtils.hasText(keyword)) {
            return null;
        }
        return searchType.getEq(keyword);
    }

}

 

페치 조인이 아니라 그냥 left join으로 comment들을 불러오고 count로 개수를 세서 Dto 생성자로 넣어주어서 해결했다.

 

깔끔해진 select 쿼리

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함