본문 바로가기
카테고리 없음

객체지향 쿼리 언어) 페치 조인 - 한계

by _비니_ 2024. 7. 30.

📌 페치 조인 - 한계

  • 페치 조인 대상에는 별칭을 줄 수 없다. (JPA 동작 방식과 관련 O)
    • EX) as m where m. ~~ … 불가능
    • 페치 조인 은 연관된 엔티티를 한 번의 쿼리로 함께 로딩하기 위한 기능임 !! 페치조인을 사용할 때 특정 엔티티나 컬렉션을 즉시 로딩하게 됨.
      • 별칭을 사용하면 명시적으로 어떤 엔티티나 컬렉션을 페치할 것인지 명확하지 않게 됨
      • 페치 조인은 주로 데이터 조회를 목적으로 사용됨. 별칭을 사용하게 되면 JPA가 해당 별칭을 가진 엔티티를 정확하게 식별하고 관리하기 어려움. JPA는 엔티티를 로딩할 때 내부적으로 엔티티 매핑 정보를 사용하여 자동으로 처리하기 때문에, 별칭이 있으면 이러한 과정이 복잡해질 수 있음
    • 하이버네이트는 가능, 가급적 사용X
    • 특정 조건에 맞는 데이터를 가져오고자 할 때는 별도의 쿼리를 작성하여 데이터를 가져오는 것 맞음
  • 둘 이상의 컬렉션은 페치 조인 할 수 없다.
    • 카테시안 곱 문제,
    • 데이터 불일치 가능성 등
  • 컬렉션을 페치 조인하면 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없다.
    • String query = "select t From Team t join fetch t.members m";

  • 컬렉션을 페치 조인하는 경우, 여러 테이블의 데이터를 조인하여 한 번에 로드하게 되는데, 이 과정에서 데이터베이스에서 반환되는 결과는 조인된 데이터의 전체 행 수가 됨.
  • 이때 페이징 API를 사용하면, 실제 로드된 데이터가 아닌 조인된 데이터 행 수 기준으로 페이징이 이루어짐. 따라서, 데이터베이스에서 올바르게 페이징이 적용되지 않으며, 이는 예상치 못한 결과를 초래할 수 있음.

 

 

  • 일대일, 다대일 같은 단일 값 연관필드는 페치조인해도 페이징 가능
String query = "select m From Member m join fetch m.team t";

>> 위 SQL 문에서 member랑 team을 뒤집음. 다대일이 되므로

  • 하이버네이트는 경고 로그를 남기고 메모리에서 페이징(매우 위험)
  • @BatchSize(size = 100)
    • 주로 지연 로딩(Lazy Loading) 과 함께 사용되어, 연관된 엔티티나 컬렉션의 데이터를 한 번에 가져오는 개수를 조절함
    • 특정 엔티티 타입 또는 컬렉션 필드에 적용할 수 있으며, 설정된 크기(batch size)만큼의 엔티티를 한 번에 로드함
      • 기본적으로 지연 로딩은 하나의 연관된 엔티티나 컬렉션의 데이터를 필요할 때마다 개별 쿼리로 로드>> 다수의 데이터베이스 쿼리 발생(성능 저하O)
        • =⇒ @BatchSize를 사용하면 이러한 문제를 완화 !!

?, ? 로 되어있음 ⇒ Team A와 B 각각의 ID가 들어가 있음. 한 번에 Team A와 연관된 member , Team B 와 연관된 member를 모두 가져온 것.

  • 연관된 엔티티들을 SQL 한 번으로 조회 - 성능 최적화
  • 엔티티에 직접 적용하는 글로벌 로딩 전략보다 우선함
    • @OneToMany(fetch = FetchType.LAZY) // 글로벌 로딩 전략
  • 실무에서 글로벌 로딩 전략은 모두 지연 로딩
  • 최적화가 필요한 곳은 페치 조인 적용 (N+1문제와 같은..)

=⇒ 이러면 대부분의 성능 문제는 잡힘

  • 모든 것을 페치 조인으로 해결할 수 는 없음
  • 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적
  • 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면, 페치 조인 보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는 것이 효과적
반응형