💡 Spring Data JPA를 사용하다보면 연관관계를 갖고 있는 두 엔티티에 대해 조회를 할 때 N+1 문제가 발생합니다.
이전 프로젝트를 진행하면서 N+1 문제가 발생할 수 있는 상황에서 직접 @Query에 Join query를 작성하면서 N+1 문제를 직접적으로 확인하고 체감하진 못하였는데요,
나중에 N+1 문제의 해결방법을 찾아보았을 때, @EntityGraph 를 사용하는 방법과 fetch join을 사용하는 방법등이 있었습니다.
그래서 단순히 이거 그냥 Join Query 사용하면 되는거 아니야? 라고 생각하고 넘어갔었습니다 🤭 하지만 일반 Join과 Fetch Join 간의 차이점을 모르고 사용했다는게 계속 마음이 걸렸습니다. 🥲
그래서 테스트를 통해 둘 간의 차이점을 알아보고자 해당 포스팅을 준비하게 되었습니다. 🔥
Hibernate:
select post0_.id as id1_0_0_, user1_.id as id1_1_1_, post0_.description as descript2_0_0_, post0_.title as title3_0_0_, post0_.user_id as user_id4_0_0_, user1_.name as name2_1_1_
from post post0_
inner join user user1_
on post0_.user_id=user1_.id
// 출력 결과
user0
user1
user2
user3
user4
@Query("SELECT p FROM Post p "
+ "LEFT JOIN User u "
+ "ON p.user.id = u.id")
List<Post> findAllByJoin();
Hibernate: select post0_.id as id1_0_, post0_.description as descript2_0_, post0_.title as title3_0_, post0_.user_id as user_id4_0_ from post post0_ left outer join user user1_ on (post0_.user_id=user1_.id)
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
// 출력 결과
user0
user1
user2
user3
user4
public class PostUserDTO {
private String userName;
private String postTitle;
}
@Query("SELECT new com.example.springbootstudy.domain.PostUserDTO(u.name, p.title) FROM Post p "
+ "LEFT JOIN User u "
+ "ON p.user.id = u.id")
List<PostUserDTO> findAllPostUserByFetchJoin();
@Test
@DisplayName("일반 Join 쿼리 와 DTO 를 사용하여 N+1 문제를 해결한다.")
void joinWithDTOTest() {
List<PostUserDTO> postUserDTOS = postRepository.findAllPostUserByFetchJoin();
postUserDTOS.stream()
.map(postUser -> postUser.getUserName())
.forEach(System.out::println);
}
Hibernate: select user1_.name as col_0_0_, post0_.title as col_1_0_ from post post0_ left outer join user user1_ on (post0_.user_id=user1_.id)
// 출력 결과
user0
user1
user2
user3
user4