경로 표현식

점을 (.)을 찍어서 객체 그래프를 탐색하는 것을 경로 표현식이라고 한다.

select m.username -> 상태 필드 
	from Member m
		join m.team t -> 단일  연관 필드
		join m.orders o -> 컬렉션  연관 필드 
where t.name = '팀A'

여기서 m.username은 단순히 필드를 불러온 값이다.

밑의 m.team의 경우에는 엔티티를 의미한다. 즉 상태필드가 아닌 추가적으로 객체 그래프에 대해서 탐색이 가능하다. 이런 것들을 단일 값 연관 필드라고 한다. @ManyToOne, @OneToOne, 대상이 엔티티(ex: m.team)

마지막의 m.orders는 하나의 엔티티가 아닌 컬랙션을 조회하는 케이스이므로 컬렉션 값 연관 필드라고 말한다. @OneToMany, @ManyToMany, 대상이 컬렉션(ex: m.orders)

이 경우들에 따라서 조회하는 방식이 크게 달라진다.



1. 경로 표현식의 특징

1) 상태 필드(state field): 경로 탐색이 끝이다. 즉, 더 이상 탐색이 불가능하다.

2) 단일 값 연관 경로: 묵시적 내부 조인(inner join) 발생한다. 탐색이 추가적으로 가능하다.

String query = "select m.team from Member m "; // 묵시적 내부 조인 발생, 성능문제 발생 가능.. 묵시적 조인 안되게 만들어야됨

이렇게 하면 묵시적 내부 조인이 발생한다. 근데 이런 묵시적 내부 조인은 나중에 성능 문제가 발생할 수 있다. 데이터베이스에서는 조인 쿼리가 나가는데, JPQL입장에서 보면 조인이 눈에 딱 안띄기 때문에 나중에 조인이 어디서 발생하는지 찾는데 시간이 오래걸릴 수 있다.

3) 컬렉션 값 연관 경로: 묵시적 내부 조인 발생, 더 이상 탐색이 불가능하다. FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색이 가능하다.

String query = "select t.members from Team t "; // 컬렉션은 .으로 뭐 탐색 불가 .size는 가능

컬랙션으로 들어가기 때문에 t.members.해서 더 이상 뭘 가져올 수 없다. size정도만 가능하다.

만약 가져오고 싶다면 아래와 같이 명시적 조인을 이용해야한다.

String query = "select m.username from Team t join t.members m";

그냥 묵시적 조인을 쓰지말고 명시적 조인을 써라!

명시적 조인 : select m from Member m join m.team t



요약

  • 가급적 묵시적 조인 대신에 명시적 조인을 사용하자.
  • 조인은 SQL 튜닝에 중요 포인트이다.
  • 묵시적 조인은 조인이 일어나는 쿼리를 한번에 떠올리기가 어렵다.