[자바 ORM 표준 JPA 프로그래밍 - 기본편] 11-3강


https://inf.run/2zDo 강의를 수강하고 작성하는 게시물입니다.


1. 패치 조인의 특징과 한계

패치 조인의 한계는 아래와 같다.

  • 페치 조인 대상에는 별칭을 줄 수 없다.
  • 둘 이상의 컬렉션은 페치 조인 할 수 없다.
  • 컬렉션을 페치 조인하면 페이징 API(setFirstResult, setMaxResults)를 사용할 수 없다.

하나씩 알아보자.

1.1. 별칭주기

패치 조인에는 별칭을 줄 수 없다. (하이버네이트는 가능하지만 가급적 사용하지 않도록 한다.)

String query "select t from Team t join fetch t.members as m";

위 코드의 as m 부분처럼 별칭을 지정하는 행위를 할 수 없다.

where m.username 이런식으로 쓰지 말라는 말이다.

별칭을 지정하는 것은 연관된 것을 다 끌고 오겠다는 말이다.

예를들어 팀A에 5명 있는데 팀원중의 한명만 가져와서 조작할 경우 나머지 4명이 누락되어있기 때문에 잘못동작할 수 있기 때문에 사용 안하는 것을 추천한다.

결국 추려서 사용하고 싶을경우 팀에서 멤버를 조회하는 것이 아니라 멤버를 조건을 부여하여 특정 멤버만 조회해야한다.

1.2. 둘 이상의 컬렉션

일대다도 데이터가 뻥튀기가 되는데 ‘일대다 대다’ 가 되므로 데이터 뻥튀기가 뻥튀기 되므로(?) 데이터의 정합성이 문제가 될 수 있다. 그러므로 사용하면 안된다.

1.3. 페이징 API를 사용

일대일, 다대일 같은 단일 값 연관 필드들은 패치조인을 사용해도 페이징을 사용할 수 있다.

그러나 일대다의 경우 패치조인을 사용하면 페이징을 사용할 수 없다. 페이징은 DB의 입장에서 만들어 주는 것이므로 데이터 뻥튀기가 되어 출력되기 때문이다.

JPA에서 처리해줄 경우 어떤 데이터가 유효한 데이터인지 구분하기 어렵기 때문에 사용하지 않는것을 추천한다. 만약 JPA가 처리한다고 해도 메모리로 모든 데이터를 끌고 온 후 처리를 하기때문에 매우매우매우 위험한 상황이다. 사용하지 않는것을 추천한다.

1.3.1. 방향 바꿔 페이징 사용하기

페이징을 사용하고 싶다면 일대다를 다대일 방향으로 바꿔 사용하는 방법이 있다.

select m from Member m fetch join m.team

1.3.2. 과감히 패치 조인을 삭제하기

String query = "select t From Team t";

List<Team> result = em.createQuery(query, Team.class)
    .setFirstResult(0)
    .setMaxResults(2)
    .getResultList();

우선 패치조인을 과감히 삭제하고 지연로딩으로 불러온다. 그러면 성능이 안나올텐데

엔티티 선언 부분에서 아래처럼 설정한다.

@BatchSize(size = 100)
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();

지연로딩으로 가져올때 나중에 가져오는 것이 아닌 쿼리를 100개씩 가져오도록 설정하는 것이다.

위처럼 엔티티 선언부분이 아닌 글로벌하게 세팅할 수도 있다.

<property name="hibernate.default_batch_fetch_size" value="100" />

위의 속성값을 추가하면 된다. 값은 1000이하 정도로 적당히 부여하면 된다.

1.3.3 DTO로 쿼리를 직접짜기

DTO로 뽑아도 정제를 해줘야하기때문에 만만치 않다.

2. 한계로 인해 패치 조인 사용시 생각해야할 점

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

JPA의 70~80프로의 성능 문제는 N+1이 차지한다고 볼 수 있다. 패치조인을 적절히 사용한다면 성능 해결이 될 것이다.

3. 정리

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

댓글 남기기