JPA 관련 흔하게 발생하는 문제점들에 대한 해결법 메모


몇년 전, 처음 JPA를 사용했을 때 n+1은 가장 처음에 겪었던 문제였다. 그당시 문제를 겪고 찾았던 메모를 옮겨놓았다.
가끔 지나쳐온 동료 코드에도 디버그 쿼리로 보면 이런 부분이 있기도 했는데, (간단한거 조회였긴 했지만..) 그만큼 주의하지 않으면 빈번하게 발생하는 문제이기도 하다.


1. n+1. 조인 시 연관 개체 수만큼 쿼리 발생하는 문제

연관관계 매핑에서 상위 객체 조회시 하위 객체 수만큼 쿼리가 발생하는 문제다.

해결 방법

fetch join(inner), EntityGraph(left outer), batch size 조절, querydsl 등등 으로 해결한다.

오래 전 관련해서 메모한 JPA관련메모, QueryDSL 샘플 및 샘플 프로젝트 코드(private)


2. 페이징 처리 시 풀스캔(전체 로우 조회) 하는 문제

fetch join + paging(limit)시 의도와 다르게 모든 로우를 조회해 와서 클라이언트 페이징 처리 하여 보여주는 경우가 생긴다.

JPA에서 @ToMany 관계에 대해 Paging + fetch join을 수행할 때, One Entity 기준으로 Many Entity에 대한 데이터를 join하게 되어 데이터의 수가 변한다. ex) Review 2개, Image 3개일 때 row는 총 6개가 생김. (2 != 6) 따라서 JPA는 어떤 데이터를 기준으로 Paging을 수행해야 하는 지 알 수 없게 되어 발생한다.

  • @xToOne 애너테이션을 통해 형성된 관계인 경우 테이블 조인에 따라 데이터 수가 변경되지 않으므로 페이징 처리가 가능 합니다.
  • @xToMany 애너테이션을 통해 형성된 관계인 경우 테이블 조인에 따라 데이터가 변경되어 페이징 처리와 페치 조인이 동시에 불가능 합니다.

해결 방법

  1. fetch join 제거 후 배치 사이즈 조절로 in 처리하기
    spring.jpa.properties.hibernate.default_batch_fetch_size=10
    
  2. ManyToOne 형태로 fetch paging 조회한다. (조회의 방향을 바꿈)
  3. QueryDSL 이용하여 명시적으로 fetch join (무난)