잡동사니

Fetch join의 대상은 on, where 등에서 필터링 조건으로 사용하면 안됩니다. 본문

IT/JPA

Fetch join의 대상은 on, where 등에서 필터링 조건으로 사용하면 안됩니다.

yeTi 2022. 6. 27. 18:07

안녕하세요. yeTi입니다.
오늘은 JPA를 사용하면서 자주 사용하는 Fetch Join 의 특성에 대해 알아보고자 합니다.

공부 계기

공부가 부족한 탓에 엔티티의 @OneToOne 관계 설정 후 fetch join 으로 조인 대상을 필터링 하려는 시도를 했습니다..ㅜ
하지만 원하는 결과가 나오지 않아 원인을 찾기 위해 구글링을 하게 되었고 인프런에 계신 김영한님의 답변들을 보면서 궁금증을 해소하게 됐습니다.

JPA 강의도 정주행을 해야하지만 현재 보고 있는 이펙티브 자바 완벽 공략 1부 를 완강 후 보도록 해야겠습니다.

원인

JPA 표준 스펙에는 fetch join 대상에 별칭이 없지만, 하이버네이트허용합니다. 즉, fetch join 대상에 별칭을 사용은 할 수 있지만 DB 일관성 문제들이 발생할 수 있으니 주의해서 사용해야 합니다.

Fetch join의 결과는 연관된 모든 엔티티가 있을것이라 가정하고 사용해야 합니다. 만일 fetch join에 별칭을 잘못 사용해서 컬렉션 결과를 필터링 해버리면, 객체의 상태와 DB의 상태 일관성이 깨지게 됩니다.

결론적으로 JPA의 엔티티 객체 그래프는 DB와 데이터 일관성을 유지함으로써 DB와 데이터 일관성을 유지하려고 합니다.

조회 조건별 상태

즉시 로딩(EARGR로 설정)

  1. 멤버 전체를 조회하기 위해 JPQL 실행 select m from member m
  2. JPQL은 EAGER와 무관하게 SQL로 그대로 번역 -> select m.* from member
  3. JPQL 결과가 member만 조회하고, team은 조회하지 않음
  4. member와 team이 즉시 로딩으로 설정되어 있기 때문에 연관된 팀을 각각 쿼리를 날려서 추가 조회 (N+1)

지연 로딩(LAZY로 설정)

  1. 멤버 전체를 조회하기 위해 JPQL 실행 select m from member m
  2. JPQL은 EAGER와 무관하게 SQL로 그대로 번역 -> select m.* from member
  3. JPQL 결과가 member만 조회하고, team은 조회하지 않음
  4. member와 team이 지연 로딩으로 설정되어 있기 때문에 프록시 객체를 넣어두고, 실제 회원은 팀은 조회하지 않음
  5. 실제 team을 사용하는 시점에 쿼리를 날려서 각각 조회 (N+1)

fetch join 또는 엔티티 그래프(EAGER, LAZY 상관 없음)

  1. 멤버와 팀을 한번에 조회하기 위해 JPQL+fetch join 실행 select m from member m join fetch m.team
  2. JPQL에서 fetch join을 사용했으므로 SQL은 멤버와 팀을 한 쿼리로 조회 -> select m., t. from member join team ...
  3. JPQL 결과가 member와 team을 한꺼번에 조회함
  4. member와 team이 fetch join으로 한번에 조회되었으므로 N+1 문제가 발생하지 않음

참고적으로, 일반 JOIN은 select시점에 member만 조회하기 때문에 일반 member select와 같습니다.

해결

fetch join의 대상은 on, where 등에서 필터링 조건으로 사용하면 안된다.

그러면 어떻게 해결할 수 있을까요? 바로 엔티티가 아닌 그냥 값으로 조회하면 됩니다. 엔티티는 객체 그래프를 유지하고 DB와 데이터 일관성을 유지합니다. 그런데 엔티티가 아닌 일반 값들은 그럴 필요가 없습니다.

JPA에서 모든 연관관계는 꼭! LAZY로 설정해야합니다. 실무에서 EAGER는 없다고 생각하시는 것이 좋습니다. 그렇게 해야 member만 필요해서 조회할 때, member만 조회가 됩니다.

그런데 때때로 특정 기능에서는 member와 team이 함께 필요한 경우가 있습니다. 이때 그 상황에 맞는 로직에서 fetch join을 사용하면 n+1 문제를 해결할 수 있습니다.

참고 자료

Comments