개괄
JPA 강의를 듣다 보면 나처럼 두뇌가 느리게 굴러가는 사람들은 이상한 결론에 도달할 것이다.
"음... Querydsl만 있으면 jpa를 완벽 해결할 수 있겠구만"
"음... fetch join만 사용하면 join과 관련된 최적화 이슈를 다 해결할 수 있겠구만"
맞는 말이긴 하다.
아마 "Spring Boot를 배워놓으면 Spring은 배우지 않아도 될거야, Spring Boot가 다 해결해주니까!"와 비슷한 개념일 것이다.
보통 N+1 문제를 해결하기 위해
ManyToOne을 Lazy Loading으로 걸어주고 페치 조인으로 추가쿼리가 나가지 않게끔 해결하곤 한다.
그러나 이게 습관이 되면 그냥 다 fetch join을 걸어준다.
그러나 fetch join은 연관된 정보를 미리 다 땡겨옴으로서 오히려 단순 조회에서는 성능이 더 안 나올때도 있다.
예를 들어 다음의 엔티티 테이블이 있다고 생각해보자.
[Project] 1 : N [Project_User] N : 1 [User]
Project와 User의 다대다 관계를 해결하기 위해 일대다 관계로 두번 나누었고, 행위엔티티를 기록하기 위해 Project_User라는 테이블을 만들어 주었다.
그리고 User에 있는 id와 연관된 모든 project를 가지고 오고 싶다고 생각해보자.
JPQL로 나타내면
"select p from Project p join p.projectUserList pu where pu.user.userId = :userid"일 것이다.
그러나 나는 여기에 join fetch를 걸어 주어서 다음과 같은 JPQL문이 나가게 되었다.
"select p from Project p join fetch p.projectUserList pu where pu.user.userId = :userid"
join fetch를 걸면 쿼리가 2방이 나가게 된다. 살펴보자.
Hibernate:
select
...
projectuse1_.project_id as project_2_5_1_,
projectuse1_.user_id as user_id3_5_1_,
projectuse1_.project_id as project_2_5_0__,
projectuse1_.id as id1_5_0__
from
project project0_
inner join
project_user projectuse1_
on project0_.project_id=projectuse1_.project_id
where
projectuse1_.user_id=?
Hibernate:
select
...
from
users user0_
where
user0_.user_id=?
project에 대한 정보와 projectuser에 대한 정보를 select하는 쿼리와 동시에 projectuser까지 전부 조회해버리는 쿼리가 나가서 결국 user에 대한 정보까지 긁어오는 것을 볼 수 있다.
그러나 user까지 조회할 것이 아니라면 단순히 join만 걸어주면 쿼리를 훨씬 절약하게 된다.
join만 걸고 나가는 쿼리는 다음과 같다.
Hibernate:
select
...
from
project project0_
inner join
project_user projectuse1_
on project0_.project_id=projectuse1_.project_id
where
projectuse1_.user_id=?
단순히 프로젝트에 대한 정보만 가지고 오는 것을 볼 수 있다.
물론 이 조회에서 더 나아가서 user info까지 말아서 데이터를 전송해야 하는 입장이면 join fetch가 맞다.
그러나 프로젝트에 대한 정보만 조회하는데 굳이 쿼리를 한 번 더 쓸 일은 아닌 것 같다.
결국 Join과 Fetch join에 대한 이해가 있어야 최적화도 가능하다.
뭐든지 알고 쓰자.
'DB > JPA' 카테고리의 다른 글
QueryDsl Custom Repository 명명 규칙 (0) | 2023.03.31 |
---|---|
왜 GenerationType.Identity를 써 주는 것일까? (0) | 2023.02.23 |