문제 상황
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
이유
- Querydsl 에서 on() 절로 매핑하면 두 엔티티가 연관관계라는 것을 인식하지 못한다.
- 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
'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 |