(QueryDsl) 페이지 매김 + FetchJoin

# 문제 상황

.offset 및 .limit로 페이지 매김을 수행하는 querydsl 쿼리를 작성했습니다. 페이징 가능한 개체를 사용합니다. N+1 문제를 해결하기 위해 연관된 엔티티는 fetchJoined입니다.

List<FarmLog> farmLogs = jpaQueryFactory
            .selectFrom(farmLog)
            .leftJoin(farmLog.likers).fetchJoin() // 좋아요한 사람들 fetch join
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(farmLog.createdAt.desc())
            .fetch();

쿼리 결과가 나오면?

# 컬렉션 가져오기로 지정된 firstResult/maxResults; 메모리의 응용 프로그램

경고가 나타납니다.


일대다 관계가 여러 개 있는 상황에서 페치 조인과 유사하게 전체 쿼리 결과를 메모리에 로드한 다음 페이지 매김을 수행하기 때문으로 보입니다. 최대 절전 모드에서 쿼리 문을 보면 offset 또는 limit 키워드가 전혀 표시되지 않습니다.


https://javabom.104

fetchJoin이 있는 경우 쿼리 매개 변수는 Hibernate 쿼리 문에서 null 값으로 입력된 것으로 나타납니다.

# 해결 방법: 쿼리 분할

// limit 절만 사용할 query 따로 뺌
List<Long> farmLogIds = jpaQueryFactory.select(farmLog.farmLogId)
            .from(farmLog)
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .orderBy(farmLog.createdAt.desc())
            .fetch();

// fetchJoin
List<FarmLog> farmLogs = jpaQueryFactory.selectFrom(farmLog)
            .leftJoin(farmLog.likers).fetchJoin()
            .where(farmLog.farmLogId.in(farmLogIds))
            .fetch();

1) pagination을 적용하여 entity id만 추출하는 쿼리

2) 해당 ID 개체 및 fetchJoin 가져오기 쿼리

두 개를 나눠서 얻은 결과다.

실제로 동일한 요청에 대해 동일한 쿼리가 두 번 발행됩니다.

쿼리 2개 던지기 vs. N+1 실행

무엇을 포기하느냐에 달려 있는 것 같습니다.