JPA

JPA - fetchJoin, Inner join

jaewoo 2023. 3. 3. 19:12

 

일반 inner join 또는 left join을 사용할 경우 join fetch와 같은 쿼리가 실행된다. 하지만 동작결과나 사용하는게 다르다.

 

일반 Join

- 다른 Entitiy를 join해도 join한 entitiy는 영속성 컨텍스트에서 관리하지 않는다. select 한 주체가 되는 entitty만 관리하기 때문에 @OneToMnay 필드에 접근할 경우 새로운 쿼리가 한번 더 일어나야 한다. (여기서 Transcational로 묶여있지 않다면 no Session 에러가 발생한다)

 

fetch join

- 주체가 되는 entitiy뿐만 아니라 join fetch를 사용한 entitiy도 모두 영속성 컨텍스트에서 관리한다.

- 모두 영속성 컨텍스트에서 관리하기 때문에 join fetch 한 다른 entitiy를 조회해도 N+1 문제가 발생하지 않는다.

- 쿼기가 나갈 때 @OneToMany까지 모두 불러온다.

- @OneToMany 를 fetch join으로 불러오는 건 1개만 가능한데 다른 설정을 한다면 더 가져올 수 있다.

- 즉 이말은 @ManyToOne은 계속 가져올 수 있다.

 

 

hotel - review  1:N

hotel - room     1:N

 

전형적인 join이 두 개가 필요한 경우이다.

 

 

 

만약 둘 다 일반 inner join으로 가져올 경우

inner join으로 묶은 쿼리가 한 번 일어나고 뒤에 

각각 엔티티를 가져오는 쿼리가 한번씩 더 일어난다.

그렇기에 where 조건에만 해당 엔티티를 사용할 것이 아니고 직접 데이터로 쓸거라면 당연히 fetch join으로 불러와야한다.

그리고 join할 때 distnict를 사용하여 중복객체를 제거해줘야 한다. 

 

 

distnict의 중요성

 

distnict에 다른 경우를 예로 보면(테스트 케이스이므로 이해용으로만 보면된다.)

 

 

 

Member(1)  MemberRole(N) 해당 관계에서 fetch join중 inner join을 사용할 경우

데이터가 어떻게 들어오는지 보려한다.

각 데이터를 뽑아보면

 이런식으로 출력되는데 여기서 중요한건 Member에 데이터는 2개이고 MemberRole데이터가 8개라는 사실이다. 그래서 8개가 들어와 버렸는데 이 상황을 실제 데이터로 살펴본다면 

inner join으로 불러오면 이런 결과가 나온다. 

당연한 결과인 거 같다. member_role 테이블에 email과 매칭되는 값이 계속 있으니 row가 증가할 수 밖에 없다.

 

여기서

distinct

를 사용할 경우

이렇게 쿼리를 실행하면 결과가 달라질까?

결과는 아니였다. 각 row들은 중복된 값이 아니기 때문이다. 그렇다면 JPQL에서는 값이 달라질까?

JPQL에서 사용할 때는 값이 줄어드는 걸 알 수 있다.

사실 이런 부분도 left Join을 쓰면 애초에 저런 중복된 값들이 나오지 않는다. 하지만 성능 상 inner join을 써야할 경우 데이터가 많은 상태에서는 위험할 수도 있다. 지금 테스트 경우에는 많아봤자 권한은 최대 4개였지만 만약 게시글과 댓글이었다면.... 게시글이 1개에 댓글 100개일 경우 게시글을 페치조인으로 불러들이는데 100개에 중복된 데이터가 들어와버릴 수 수 있다. 그렇기에 inner join을 JPQL에서 페치조인으로 사용할 경우 distinct는 필수이다.

 

위에서 본 것처럼 DB 데이터가 join으로 불러올 경우 실제 DB에서는 데이터가 확 늘어나기에 페이징처리가 불가능하다. DB에서는 row가 4개로 잡혀서 페이징이 우리가 원하는 결과가 나오기 어렵다. 그렇기 때문에 만약 페이징 처리를 하려고 한다면 하이버네이트가 경고 로그를 내보낸다. 

'JPA' 카테고리의 다른 글

JPA - Querydsl로 max값 뽑기  (0) 2023.05.04
Redis - 개념 및 Spring에서 사용  (1) 2023.01.25
JPA - JPQL ORDER BY  (0) 2023.01.17
JPA - 연관관계 Insert Query 줄이기  (0) 2022.12.19