# 문제 상황
.offset, .limit을 이용하여 페이지네이션을 진행하는 querydsl 쿼리를 작성했다. Pageable 객체를 이용했다. N+1 문제 해결을 위해 연관 관계 엔티티를 fetchJoin까지 한 상황이다.
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 specified with collection fetch; applying in memory
WARN이 뜬다.

일대다 관계가 여러 개인 상황에서 fetch join을 했을 때와 비슷하게, 쿼리 결과 전체를 메모리에 올려놓은 뒤 pagination을 진행해서 그런듯. 실제로 hibernate에서 나간 쿼리문을 보면 offset이나 limit 키워드는 전혀 보이지 않는다.

https://javabom.tistory.com/104
fetchJoin이 있을 때 query parameter가 hibernate 쿼리문에 null값으로 들어가는 듯하다. 쿼리문 자체에 offset + limit이 들어가는게 아니라 전체 결과를 메모리에 올려 어플리케이션 단계에서 paging을 진행하고 있다, 따라서 메모리 오버가 발생할 위험성이 있다.. 라는 경고이다.
# 해결법 : 쿼리 나누기
// 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 적용해서 엔티티 id만 뽑아오는 쿼리
2) 해당 id 객체를 가져와 fetchJoin하는 쿼리
둘을 나눠서 결과 result를 구했다.
같은 요청에 대해서 사실상 같은 쿼리가 두 번 나가는 일이다.
2번 쿼리 날리기 vs N+1 겪기
무엇을 포기하냐에 따라 다를듯.
# 문제 상황
.offset, .limit을 이용하여 페이지네이션을 진행하는 querydsl 쿼리를 작성했다. Pageable 객체를 이용했다. N+1 문제 해결을 위해 연관 관계 엔티티를 fetchJoin까지 한 상황이다.
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 specified with collection fetch; applying in memory
WARN이 뜬다.

일대다 관계가 여러 개인 상황에서 fetch join을 했을 때와 비슷하게, 쿼리 결과 전체를 메모리에 올려놓은 뒤 pagination을 진행해서 그런듯. 실제로 hibernate에서 나간 쿼리문을 보면 offset이나 limit 키워드는 전혀 보이지 않는다.

https://javabom.tistory.com/104
fetchJoin이 있을 때 query parameter가 hibernate 쿼리문에 null값으로 들어가는 듯하다. 쿼리문 자체에 offset + limit이 들어가는게 아니라 전체 결과를 메모리에 올려 어플리케이션 단계에서 paging을 진행하고 있다, 따라서 메모리 오버가 발생할 위험성이 있다.. 라는 경고이다.
# 해결법 : 쿼리 나누기
// 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 적용해서 엔티티 id만 뽑아오는 쿼리
2) 해당 id 객체를 가져와 fetchJoin하는 쿼리
둘을 나눠서 결과 result를 구했다.
같은 요청에 대해서 사실상 같은 쿼리가 두 번 나가는 일이다.
2번 쿼리 날리기 vs N+1 겪기
무엇을 포기하냐에 따라 다를듯.