Files
document-haness/docs/n+1liner/tech-log-studio/jpa-feed-query-performance/decision/decision-batch-fetch-for-entity-graph.md
T

3.0 KiB

id, kind, slug, title, topic, project, status, studio, decisionStatus
id kind slug title topic project status studio decisionStatus
08a74b35-10c3-4874-8fbc-209b0b6e942e PROJECT_DECISION batch-fetch-for-entity-graph Entity Graph 조회에는 Batch Fetch를 사용한다 JPA 피드 조회 성능 Liner N + 1문제 게시 전 https://hyeonworks.com/studio/documents/08a74b35-10c3-4874-8fbc-209b0b6e942e/edit PROPOSED

Entity Graph 조회에는 Batch Fetch를 사용한다

엔티티를 그래프로 조회해야 하는 경로에서는 컬렉션 fetch join 대신 배치 페치를 쓴다. 엔티티만 페이징해 DB LIMIT을 살리고 지연 연관은 부모 키를 모아 IN으로 채운다.

근거

  • Fetch Join · Batch · Projection 선택 기준 세 전략의 역할을 나눈 기준이다.
  • Collection Fetch Join Pagination의 In-memory Paging fetch join과 페이징이 함께 서지 못하는 것을 확인한 기록이다.
  • Projection 이후에도 1,509행을 읽은 Row Over-fetch 배치가 남긴 엔티티 과적재를 확인한 기록이다.

결정문

엔티티 그래프가 필요한 조회에서는 컬렉션을 fetch join하지 않고 배치 페치 크기를 설정해 지연 연관을 IN으로 묶는다.

배치 설정의 적용 범위를 명시한다. 세션 전체에 거는 설정은 기존 측정에 영향을 주므로 격리된 범위에 둔다.

판단 이유

fetch join은 부모와 자식을 한 결과에 합쳐 행을 곱했고, 그 때문에 DB가 부모 기준 LIMIT을 적용할 수 없었다. 배치는 부모만 먼저 페이징하고 자식은 별도 쿼리로 가져오므로 두 문제가 함께 풀린다.

측정에서 총 획득 statement가 크게 줄었다. 왕복은 부모 수를 배치 크기로 나눈 올림값이 된다. 컬렉션뿐 아니라 즉시 로딩 연관도 같은 배치에 묶였다.

로드한 부모 엔티티도 데이터셋 전체가 아니라 페이지 크기에서 멈췄다. 인메모리가 아니라 DB에서 LIMIT으로 부모를 먼저 자른 결과다.

실행계획에서도 부모 페이징에 Limit 노드가 붙고 자식 IN은 부모와 자식을 곱하지 않는 준조인으로 나타났다. 앞 단계에서 본 카테시안과 인메모리 페이징이 모두 사라졌다.

영향

  • 지표 해석이 달라진다. 배치를 적용하면 초기화 컬렉션 수가 SQL 수와 같지 않다. 획득 statement 수와 컬렉션 수를 함께 보고 판단해야 한다.
  • 배치 크기 설정은 세션 전체에 영향을 준다. 기존 기준선 측정을 유지하려면 설정 범위를 격리해야 한다.
  • 엔티티는 여전히 통째로 하이드레이트된다. 화면에 필요하지 않은 컬럼까지 영속 객체로 올라온다. 이 비용은 배치가 풀지 않는다.
  • 배치 크기를 정해야 한다. 크기가 크면 IN 목록이 길어지고 작으면 왕복이 늘어난다.
  • 특정 연관에만 배치를 걸 수도 있지만 그러면 매핑 자체가 바뀐다. 기준선과 비교하려면 설정으로 두는 편이 낫다.