팀과 user의 일대다 관계가 있다.
5개의 팀과 5명의 유저가 있다
team repo에서 findAll()을 하면 하나의 쿼리만 나갈것으로 예상된다.
-> select from team;
하지만 추가적으로 team의 개수만큼의 쿼리가 더 발생한다.
왜그러는것일까?
1. findAll -> select t from Team t 라는 jpql구문이 생성되고 해당구문을 분석하여 select from team 이라는 sql이 생성된다
2. db의 결과를 받아서 team엔티티의 인스턴스를 생성한다. 디비에 5개의 팀이 있으니 5개의 인스턴스를 생성한다
3. team과 연관되어있는 user들도 로딩을 해야한다
4. 영속성 컨텍스트에 연관된 user가 있는지 확인한다
(만약여기서 연관된 user하나만 있으면 쿼리가 하나 덜 나가게되는것일까?
아니면 똑같을까?)
5. 영속성컨텍스트에 없다면 2에서 만들어진 team인스턴스개수(5개)에 맞게
select * from user where team_id =? 라는 sql구문이 생성된다(n+1문제발생)
근데.. jparepository상속받아서 만들은 인터페이스의 구현체는 findall할때
fetchjoin을 안사용하는거잖아요..? 근데 그럼 n+1문제가 발생하게돼요.
음.. 이 문제가 이렇게나 유명한데 왜 아직도 fetchjoin을 jparepository구현체에서 안사용하고 있는거예요.,...?
n+1은 해당 엔티티의 구현 상태에 따라 발생하는거고기본적인 JpaRepository가 그거를 알수는 없기 때문에보편적인 개념을 추상화해놓은거지 개발자마다 서로 다르게 구현한 엔티티까지 인식을 해서 만들어줄수는 없죠
그런데 jparepository의 findById는 연관된 객체를 즉시로딩해놨으면 left outer join 해서 가져오는듯 ? (확실x)
서로를 참조하는 테이블인 team, member가 모두 eager이기 때문에
===============1
Hibernate:
select
member0_.member_id as member_i1_7_0_,
member0_.age as age2_7_0_,
member0_.group1_id as group6_7_0_,
member0_.code as code3_7_0_,
member0_.zip_code as zip_code4_7_0_,
member0_.name as name5_7_0_,
member0_.team_id as team_id7_7_0_,
group1x1_.group1_id as group1_5_1_,
group1x1_.name as name2_5_1_,
team2_.team_id as team_id1_12_2_,
team2_.name as name2_12_2_
from
member member0_
left outer join
group1 group1x1_
on member0_.group1_id=group1x1_.group1_id
left outer join
team team2_
on member0_.team_id=team2_.team_id
where
member0_.member_id=? //일단 member 하나를 조회하는 쿼리를 날렸고
Hibernate:
select
members0_.team_id as team_id7_7_0_,
members0_.member_id as member_i1_7_0_,
members0_.member_id as member_i1_7_1_,
members0_.age as age2_7_1_,
members0_.group1_id as group6_7_1_,
members0_.code as code3_7_1_,
members0_.zip_code as zip_code4_7_1_,
members0_.name as name5_7_1_,
members0_.team_id as team_id7_7_1_,
group1x1_.group1_id as group1_5_2_,
group1x1_.name as name2_5_2_
from
member members0_
left outer join
group1 group1x1_
on members0_.group1_id=group1x1_.group1_id
where
members0_.team_id=? //member가 가진 team이 즉시로딩이라 로딩하려고하는데 team은 member를 또 즉시로딩해서 그거 처리
===============2
왜 findAll을 하게 되면 각각의 쿼리가 따로따로 나가게되고 findById를하게 되면 left outer join을쓰는거지?
https://brunch.co.kr/@springboot/595
오늘 설명해볼 주제는 다음과 같아요
1. n+1문제