경로 표현식 용어 정리
- 경로 표현식: .(점)을 찍어 객체 그래프를 탐색하는 것
- 상태 필드
- 단순히 값을 저장하기 위한 필드 ex) m.username
- 경로 탐색의 끝, 탐색X
연관 필드(association field): 연관관계를 위한 필드
- 단일값 연관 필드
- @ManyToOne, @OneToOne, 대상이 엔티티(ex: m.team)
- 묵시적 내부 조인(inner join) 발생, 탐색O
- 컬렉션 값 연관 필드
- @OneToMany, @ManyToMany, 대상이 컬렉션(ex: m.orders)
- 묵시적 내부 조인 발생, 탐색X
- FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능
- 쿼리에서 t.members.username 이런 식으로 사용할 수 없음(탐색X)
실무 조언
- 가급적 묵시적 조인 대신에 명시적 조인 사용!!
- 조인은 SQL 튜닝에 중요 포인트
- 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어려움
페치 조인(실무에서 매우매우 중요!)
- SQL 조인 종류X
- JPQL에서 성능 최적화를 위해 제공하는 기능
- 연관된 엔티티나 컬렉션을 SQL 한 번에 함게 조회하는 기능
- join fetch 명령어 사용
- 페치 조인 ::= [LEFT [OUTER] | INNER] JOIN FETCH 조인 경로
엔티티 페치 조인
- 회원을 조회하면서 연관된 팀도 함께 조회(SQL 한 번 에)
- SQL을 보면 회원 뿐만 아니라 팀(T.*)도 함께 SELECT
- [JPQL] select m from Member m join fetch m.team
- [SQL] SELECT M.*, T.* FROM MEMBER M INNER JOIN TEAM T ON M.TEAM_ID = T.ID
페치 조인과 일반 조인의 차이
- 일반 조인 실행시 연관된 엔티티를 함께 조회하지 않음.
- 페치 조인을 사용할 때만 연관된 엔티티도 함께 조회(즉시 로딩)
- 페치 조인은 객체 그래프를 SQL 한번에 조회하는 개념
- 일반 조인
- [JPQL]
select t from Team t join t.members m where t.name = '팀A' - [SQL]
SELECT T.* FROM TEAM T INNER JOIN MEMBER M ON T.ID = M.TEAM_ID
WHERE T.NAME = '팀A'
- [JPQL]
select m from Member m
- Member와 Team은 다대일 관계이며, 지연 조인을 적용시켰음.
- 아래 쿼리를 보면 team의 name을 조회했을 때 쿼리문이 나간 걸 확인
- user2의 팀 조회는 팀A가 이미 영속성 컨텍스트에 존재하기 때문에 쿼리문이 나가지 않음.
- N+1 문제가 발생할 수 있음 (1번을 조회하기 위해 쿼리를 1개 날렸는데 N개 만큼 쿼리가 더 나가는 걸 의미)
select m from Member m join fetch m.team
- 데이터를 한번에 가져옴.
컬렉션 페치 조인
- 일대다 관계, 컬렉션 페치 조인
- [JPQL]
select t from Team t join fetch t.members where t.name = '팀A' - [SQL]
SELECT T.*, M.* FROM TEAM T
INNER JOIN MEMBER M ON T.ID = M.TEAM_ID
WHERE T.NAME = '팀A' - 원래는 member가 2명이니 값이 3개 출력돼야 정상이지만, 하이버네이트 6부터는 distinct가 자동 적용이 돼서 중복을 제거해줌.
페치 조인의 특징과 한계
- 페치 조인 대상에는 별칭을 줄 수 없다.
- 하이버네이트는 가능, 가급적 사용X
- 둘 이상의 컬렉션은 페치 조인 할 수 없다.
- 컬렉션을 페치 조인하면 페이징 API를 사용할 수 없다.
- 일대일, 다대일 같은 단일 값 연관 필드들은 페치 조인해도 페이징 가능
- 하이버네이트는 경고 로그를 남기고 메모리에서 페이징(매우 위험)
// 이거 사용 XXX
String query = "select t FROM Team t join fetch t.members as m";
페치 조인 - 정리
- 모든 것을 페치 조인으로 해결할 순 없음.
- 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적
- 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면, 페치 조인 보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 변환하는 것이 효과적
추가로 n+1 해결 방법중 하나가 batch_size가 있다고 함. 공부 예정
'JPA' 카테고리의 다른 글
[JPA API] 간단한 회원 등록, 수정, 조회 API (1) | 2024.01.23 |
---|---|
[JPQL] Named 쿼리 / 벌크 연산 (0) | 2024.01.22 |
[JPQL] 조건식, 기본 함수 (0) | 2024.01.20 |
[JPQL] 조인 (0) | 2024.01.19 |
[JPQL] 프로젝션 (0) | 2024.01.19 |