경주장

JPQL 예시와 N+1문제, 단일 값, 컬렉션 값 조인 본문

JPA

JPQL 예시와 N+1문제, 단일 값, 컬렉션 값 조인

달리는치타 2022. 1. 6. 15:44

1:N관계를 가진 team, member 엔티티에서 발생할 수 있는 여러 쿼리를 실행해보자

 


모든 멤버의 이름

String jpql = "select m.username from Member m";

Fetch 옵션을 레이지로 두었기 때문에 

SQL에서는 요청하지 않은 Team에대한 쿼리는 전혀 없이

SELECT m.username from Member m 쿼리 한방으로 이름만 잘 긁어 올 수 있었다.

 


모든 멤버

String jpql = "select m from Member m";

이때 멤버 인스턴스에는 team이 proxy로 들어가 있으며 proxy의 메소드를 호출하면

그때 jpa는 각 team id의 정보를 얻기위해 쿼리(where in문)를 발생시킨다.


모든 멤버, 조인문

String jpql = "select m from Member m join m.team";

 

마찬가지로 멤버 인스턴스에는 team이 proxy로 들어가 있으며 proxy의 메소드를 호출하면

그때 jpa는 각 team id의 정보를 얻기위해 쿼리(where in 문)을 발생시킨다.

위의 쿼리는 필요없는 join을 유발하는 잘못된 쿼리이다.


모든 멤버, 페치 조인

String query2 = "select m from Member m join fetch m.team";

조인을 하되 마치 SQL에서 TEAM과 관련된 모든 필드에 * 키워드를 활용한 것 처럼 다 끌어다 온다.

끌어 온 이후에 JPA는 마법처럼 Member의 Team엔티티를 모두 영속화 하고 채워넣는다. 프록시도 아니고 실제 Member객체이다.

 

 

 

 


모든 팀 컬렉션 조인

String query3 = "select t from Team t join t.members";
String jpql = "SELECT t FROM Member m join m.team t;

둘은 join의 순서에만 영향을 주고 같은 결과를 낸다.

Team의 Members는 안 채워져 있다!

=>

역시 Lazy옵션 때문에 다른 테이블과 매핑한 엔티티와 관련된 정보는 긁어오지 않는다. 때문에 각팀의 소속 멤버를 조회 할때마다 쿼리발생의 가능성이 생긴다. 위의 예시에서는 결과 team 3개를 루프를 돌며 멤버를 조회하려 하면 떡잎마을 방범대는 처음 한번에 team_id =1로 멤버를 모두 조회하여 영속성 컨텍스트에 보관하기 떄문에 두번째 접근 하는 시점에서는 쿼리 없이 가져 올 수 있다. 하지만 무한도전팀을 접근 할떄는 다시 쿼리가 발생한다.

 

Team의 Member 필드는 @OneToMany 어노테이션을 가지며 default가 Lazy이지만 Eager로 바꾸어 실행을 해보니  모든 연관된 엔티티를 접근 하기전에 미리 채워 놓는다는 관점에서 실행 시점의 차이만 발생하지 발생한 쿼리의 개수와 내용은 모두 같았다. (모든 팀을 접근할때)

 

 

 


모든 팀 컬렉션 페치 조인

String query4 = "select t from Team t join fetch t.members";

Join 쿼리를 날릴때 멤버의 필드까지 SELECT 문의 필드에 추가하여 다 긁어온다.

JPA는 마법처럼 Team의 members엔티티를 모두 영속화 하고 채워넣는다. 프록시도 아니고 실제 members객체이다.!

 


모든 팀 컬렉션 페치 조인 Distinct

String query5 = "select distinct t from Team t join fetch t.members";

JPQL의 Distinct 키워드는 두가지 역할을 한다.

  1.  SQL의 Distinct 키워드 삽입
  2. 반환된 결과에 대해서 요청한 엔티티의 Distinct 내부적으로 처리

Query5의 결과는 SQL에서는 위와같이 반환되지만 JPA는 내부적으로 Team의 속성에 대해서만 distinct 처리를 하기 때문에 최종 반환된 List<Team>는 2개의 Team을 가지게 된다!

 

'JPA' 카테고리의 다른 글

영속화 옵션 예시  (0) 2022.01.06
JPQL - 기본 문법  (0) 2022.01.05
값 타입  (0) 2022.01.05
프록시와 연관관계 관리  (0) 2022.01.04
고급 매핑  (0) 2022.01.04