JPQL- part3(경로표현식/fetch join)

Shaun·2021년 11월 6일
1

JPA

목록 보기
27/31

경로 표현식

1. 상태 필드 : 단순히 값을 저장하기 위한 필드

2. 연관 필드

단일 값 연관 필드
-@ManyToOne , @OneToOne, 대상이 엔티티
-묵시적 내부조인 (inner join) 발생, 탐색 가능
-여기서 탐색이란 m.team.getName() 이런식으로 더 들어갈수 있다는 의미이다

컬렉션 값 연관 필드
-@OnetToMany, @ManyToMany, 대상이 컬렉션
-묵시적 내부 조인 발생, 탐색 불가능(객체중 어떤 객체가 나올지 모르니)
-FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통
해 탐색 가능

명시적 조인 VS 묵시적 조인

1.묵시적 조인: 경로 표현식에 의해 묵시적으로 SQL조인 발생.

Member -> Team 다대일 관계시 / select m.team from Member m

2. 명시적 조인: join 키워드 직접 사용

Member -> Team 다대일 관계시/select m from Member m join m.team t

★묵시적적 조인은 쿼리문만 봐서는 조인이 나가는지 알수가 없다. 또한 일어나는 상황을 한눈에 파악하기 어렵다. 그러므로 묵시적은 권장하지 않고 명시적 조인을 가능하면 사용하자!

Fetch Join

  • SQL 조인 종류 x

  • JPQL 에서 성능 최적화를 위해 제공하는 기능

  • 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회


  • 예시를 보면 이해가 쉽다. for문으로 돌릴때 처음 DB에 쿼리를 보내 값을 가져온뒤 프록시 객체에서 team 데이터를 건드리는 순간 또 쿼리가 나간다.

  • 그동시에 1차캐쉬에 그데이터를 저장해 다음 Member2 는 1차캐시에서 값을 가져온다(쿼리문 x)

  • 다음 팀B에대해서는 새롭게 DB에 쿼리를 날려 데이터를 가져온다

  • 이렇게 2개의 데이터만 가져와도 쿼리문이 많이나가서 성능 저하를 유발한다. 이를 해결하기위해 Fetch Join을 써주자!!

  • 연관된 데이터들을 한번에 다가져온다. 그러므로 member.getTeam() 부분은 위 예시와 다르게 프록시가 아닌 진짜 객체이다. 그러므로 쿼리 횟수가 줄어든다. = 성능 증가!

컬렉션 패치 조인

  • 회원 1을 DB에서 가져올때 1차캐시에 데이터를 넣고 회원 2를 가져올때 1차캐시에서 가져오므로 참조값은 같다.

  • Fetch join 을 사용해 연관된 멤버들값을 다 가져온다.

  • 연관관계를 찾아간다라는 의미는 JPA 입장에서 데이터들이 다나온다는 가정하에 설계되있다. (데이터를 5개 가져왔는데 2개만 x)

  • 다대일의 반대방향

  • 페치조인이 ManyToOne 방향이라면 컬렉션 패치 조인은 일대다 방향이다

  • 일대다 컬렉션 패치 조인은 데이터 뻥튀기가 일어난다 왜냐하면 팀의 입장에서는 맴버가 여러개 이기때문

Distinct

  • SQL의 DISTINCT는 중복된 결과를 제거하는 명령

  • JPQL의 DISTINCT 2가지 기능 제공
    • 1. SQL에 DISTINCT를 추가
    • 2. 애플리케이션에서 엔티티 중복 제거

페치 조인 VS 일반 조인

  • 페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)

  • 페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념

페치 조인 한계 및 특징

  • 페치 조인 대상에는 별칭을 줄 수 없다.

  • 둘 이상의 컬렉션은 페치 조인 할 수 없다.

  • 컬렉션을 페치 조인하면 페이징 API(setFirstResult,
    setMaxResults)를 사용할 수 없다.

    ex) 데이터 2개+ 페이지 사이즈 1로 가져오면 데이터 하나만 인식된다.

->일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인해도 페이징 가능

->하이버네이트는 경고 로그를 남기고 메모리에서 페이징(매우 위험)

  • 엔티티에 직접 적용하는 글로벌 로딩 전략보다 우선함( ex: 지연로딩)

  • 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른
    결과를 내야 하면, 페치 조인 보다는 일반 조인
    을 사용하고 필요
    한 데이터들만 조회해서 DTO로 반환하는 것이 효과적

핵심포인트

필요없는 쿼리문 방지를 위해 지연로딩을 사용했다.
-> 연관된 테이블을 부를때 프록시부르고, 쿼리 날라가고... 낭비가 심히다!
->지연로딩으로 하되 fetch join 을 사용해 연관된 테이블이 필요할때만 한번에 불러오자!

profile
호주쉐프에서 개발자까지..

0개의 댓글