QueryDSL 사용 중, 잘못 알고 있던 내용이 있었다.
아래와 같은 쿼리를 사용했다고 가정한다.
-- JOIN
SELECT * FROM A
JOIN B ON A.id = B.a_id;
-- INNER JOIN
SELECT * FROM A
INNER JOIN B ON A.id = B.a_id;
일반적으로 SQL 문 작성 시, JOIN을 사용하면 기본적으로 INNER JOIN을 사용한다고 알고 있었다.
하지만 QueryDSL에서는 join()과 innerJoin()이 따로 존재한다.

✔️join()
- 조인할 대상이 @OneToMany 혹은 @ManyToMany 관계일 때 사용
- JPQL에서는 기본적으로 LEFT JOIN으로 처리됨
- 결과가 없는 경우에도 기준 테이블(A)의 데이터는 유지됨.
QMember member = QMember.member;
QTeam team = QTeam.team;
JPAQuery<Member> query = new JPAQuery<>(entityManager);
query.from(member)
.join(member.team, team) // 내부적으로 LEFT JOIN이 됨
.where(team.name.eq("Team A"))
.fetch();
join()을 사용하면 기본적으로 LEFT JOIN이 적용되므로, team에 해당하는 값이 없어도 member 데이터는 조회됨.
✔️innerJoin()
- 명확한 INNER JOIN을 사용해야 할 경우 사용
- 결과가 없는 경우 기준 테이블(A) 데이터도 제거됨
- join()과 달리 INNER JOIN을 강제함.
QMember member = QMember.member;
QTeam team = QTeam.team;
JPAQuery<Member> query = new JPAQuery<>(entityManager);
query.from(member)
.innerJoin(member.team, team) // 명확하게 INNER JOIN을 적용
.where(team.name.eq("Team A"))
.fetch();
innerJoin()을 사용하면 team에 매칭되는 데이터가 없는 경우 member 데이터도 결과에서 제외됨.
✔️결론
- JPA에서는 @OneToMany 관계를 INNER JOIN으로 처리할 경우 데이터가 누락될 가능성이 있어서 기본적으로 LEFT JOIN을 사용한다.
- QueryDSL은 JPA 기반으로 처리되기 때문에, QueryDSL에서도 join()을 기본적으로 LEFT JOIN으로 처리 해야한다.
- INNER JOIN을 명확하게 사용하고 싶다면 innerJoin()을 사용해야한다.
- 조인된 테이블의 값이 반드시 존재해야 하는 경우 (@ManyToOne, @OneToOne 등)에는 INNER JOIN을 사용하자.
- 쿼리 성능 최적화를 위해 INNER JOIN을 강제하고 싶은 경우인지 확인하자.