11. 객체지향 쿼리 언어2 - 중급
JPQL 경로 표현식#
- 상태 필드: 단순히 값을 저장하기 위한 필드
 - 연관 필드
- 단일 값 연관 필드
- *ToOne, 타겟 대상 엔티티가 하나
 
 - 컬렉션 값 연관 필드
- *ToMany, 타겟 대상이 컬렉션
 
 
 - 단일 값 연관 필드
 
경로 표현식#
묵시적 조인은 쓰지말자
- 상태필드: 경로 탐색의 끝, 탐색 X (. 으로 더 뻣어나갈 수 없음을 의미)
m.username에서.을 통해 더 뻣어 나갈 수 없음
 - 단일 값 연관 경로: 묵시적 내부 조인 (inner join) 발생, 탐색 O
select m.team from Member mselect m.team.name from Member m탐색 가능- 왠만하면 묵시적으로 안짜도록 주의해야함 (성능에 민감)
 
 - 컬렉션 값 연관 경로: 묵시적 내부 조인 발생, 탐색 X
select t.members from Team t(members 가 ManyToOne 으로 List)select t.members.size from Team t이런 탐색 불가select m.size from Team t join t.members m이렇게 별칭으로 가능
 
실무적 조언#
- 가급적 묵시적 조인 대신에 명시적 조인 사용
 - 조인은 SQL 튜닝에 중요 포인트
 - 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어렵다는게 문제
 
페치 조인 ⭐️#
- JPQL 성능 최적화를 위해 제공하는 기능
 - 연관된 엔티티나 컬렉션을 SQL 한 번에 함께 조회하는 기능
 - 예시
- 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 
 - jpql: 
 - 그냥 
select m from Member m을 해서 하나하나 Team을 가져오면 지연로딩이 발생해 조회할때마다 쿼리를 발생시키는N + 1문제가 발생함 - 페치 조인을 통해 쿼리 한번으로 해결
 
컬렉션 페치 조인#
- 일대다 관계
 - 예시
 
- 데이터 뻥튀기가 문제
- 이너 조인이라 row가 2개 출력되서 결과도 2개나옴
 - 하지만 객체는 같은 것을 공유하므로 같은 객체들이 나옴 (객체 중복 생성은 X)
 
 - jpql distinct 는 중복을 줄여줌
 
페치 조인의 특징과 한계#
- 페치 조인 대상에는 별칭을 줄 수 없음
- JPA 철학은 객체 그래프를 탐색한다는 것은 연관된 것 모두를 조회하는 것에 있다
 
 - 둘 이상의 컬렉션은 페치 조인 할 수 없음
- 페치 조인의 대상은 하나만
 
 - 컬렉션을 페치 조인하면 페이징 API를 사용할 수 없음
- 일대일, 다대일은 페치조인해도 페이징 가능
 - 일대다는 데이터 뻥튀기가 되서 안됨
- row 제한으로 인해 일대
다에 해당하는 데이터가 중간에 짤리는 현상이 발생해 JPA 객체의 의미를 잃음 - 강제로 하게되면 전체 데이터를 메모리로 올려서 적용하게되는데... (ㄷㄷ)
 
 - row 제한으로 인해 일대
 
 
그럼 페이징 어떻게 하지#
- 역으로 쿼리를 뒤집어서 페이지네이션을 적용
 
- 일대다 관계를 다대일 관계로 뒤집기
 
- 페치조인을 과감하게 뺌
 
- Entity 객체에 
@BatchSize(size = 100)를 통해 멤버를 100개씩 조회해서 가져와서 앱단에서 조인하게됨 hibernate.default_batch_fetch_size의 값으로 위의 기능을 글로벌하게 수행할 수 있음
- DTO로 쿼리 직접 작성하기
 
페치 조인 정리#
- 글로벌 로딩 전략은 모두 지연 로딩으로
 - 최적화가 필요한 곳은 페치 조인을 적용
 - 모든 것을 페치 조인으로 해결할 수 없음
 - 페치 조인은 객체 그래프를 유지할 때 사용하면 효과적
 - 여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야한다면,
- 페치 조인 보단 일반 조인을 사용하고
 - 필요한 데이터들만 조회해서 DTO로 반환하는 것이 효과적