본문 바로가기

BackEnd/JPA

QueryDSL에서 join()과 innerJoin() 차이

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을 강제하고 싶은 경우인지 확인하자.