QueryDSL

[JPA] Querydsl 에서 Fetch Join을 적용시키는 방법

쿠카이든 2022. 10. 15. 09:18
728x90
문제 상황

Fetch join 은 한 번의 쿼리로 JOIN 대상 테이블 데이터까지 한 번에 가져오고 영속성 컨텍스트에 넣어주기 때문에 n+1 문제를 해결하기 위한 하나의 방법이다.

그래서 fetch join 을 적용하면 실제로 그렇게 되는지 확인해보고 싶었다.

Querydsl
QBook book = QBook.book;
QPaper paper = QPaper.paper;

List<Book> bookList = jpaQueryFactory
                           .selectFrom(book)
                           .join(book).on(book.id.eq(paper.id)).fetchJoin()
                           .fetch();
생성된 SQL
SELECT      book.id
FROM        book 
INNER JOIN  paper  ON (book.id=paper.id)

SELECT   paper.id    
FROM     paper 
WHERE    paper.id=?

SELECT   paper.id    
FROM     paper 
WHERE    paper.id=?

...

..❓ n+1 문제가 발생했다.

나의 가설대로라면 첫 번째 쿼리 한 번만 실행하고 [paper] 테이블 컬럼까지 한꺼번에 조회해야하는데... 마치 Querydsl이 fetchJoin() 을 못 보고 지나친듯이 쿼리가 실행됐고 실제로 fetchJoin() 을 붙이나 안 붙이나 동일한 쿼리가 생성되었다.

해결

하루꼬박 헤매다 동료의 도움을 받았고 다음과 같이 변경하니 원하는대로 fetch join이 적용된 쿼리가 생성되었다.

.join(book).on(book.id.eq(paper.id)).fetchJoin()    →   .join(book.paper, paper)

Querydsl
   List<Book> bookList = jpaQueryFactory
                .selectFrom(book)
                .join(book.paper, paper)
                .fetch();
생성된 SQL
select
    book.id,
    paper.id
from
    book 
inner join
    paper on book.id=paper.id
이유
  1. Querydsl 에서 on() 절로 매핑하면 두 엔티티가 연관관계라는 것을 인식하지 못한다.
  2. Querydsl 에서 on() 절은 조건절을 위에 있는것이지 테이블을 엮기 위해 존재하는 것이 아니다.

위와 같이 생각한 이유는 HQL 공식 문서를 읽어 보고 알았다.

Querydsl 에서 SQL이 생성되기까지 다음의 변환을 거친다.

Querydsl → JPQL → HQL → SQL

HQL(Hibernate Query Language) 는 하이버네이트에서 사용하는 객체 지향적인 쿼리 언어로 HQL 구문 하나하나를 파싱해 SQL로 변환된다.

org.hibernate.hql.internal.ast.QueryTranslatorImpl.java

QueryTranslatorImpl.java

그럼 Querydsl 로부터 변환된 HQL을 확인해보자

정상적으로 fetch join 적용된 HQL

Querydsl

.join(book.paper, paper)

HQL

SELECT      book 
FROM        Book book   
INNER JOIN  fetch book.paper as paper

참고 : [JPA] Querydsl 에서 Fetch Join 적용 안되는 이유 (tistory.com)

 

[JPA] Querydsl 에서 Fetch Join 적용 안되는 이유

문제 상황 Fetch join 은 한 번의 쿼리로 JOIN 대상 테이블 데이터까지 한 번에 가져오고 영속성 컨텍스트에 넣어주기 때문에 n+1 문제를 해결하기 위한 하나의 방법이다. 그래서 fetch join 을 적용하면

elsboo.tistory.com

 

728x90

'QueryDSL' 카테고리의 다른 글

queryDsl로 like 문 구현  (0) 2022.09.19
QueryDSL 페이징 방법  (0) 2022.07.16
페이징 (feat.QueryDSL)  (0) 2022.06.25
동적 쿼리 - BooleanBuilder 사용  (0) 2022.06.25
(QueryDSL) 동적쿼리(feat. BooleanBuilder)  (0) 2022.06.18