본문 바로가기
Trouble

[QueryDSL] 컬렉션 fetchJoin 페이징 applying in memory

by 되고싶은노력가 2024. 8. 8.

 

firstResult/maxResults specified with collection fetch; applying in memory

 

QueryDSL을 사용하는 도중 로컬 환경에서 테스트할 때는 발견하지 못하다가 서버 배포 단계에서 나타난 에러이다. 


# 원인

 

일대다 관계, 혹은 컬렉션 패치 조인을 하게 된다면 데이터가 뻥튀기 되는 카테시안 곱 이 발생하게 된다. 이 때 Limit을 사용하여 페이징을 하게 된다면 데이터를 예측할 수 없기에 모든 데이터를 메모리로 가져와 처리하게 된다. 만약 데이터가 많아지게 된다면 성능에 문제가 생길 수 있다.

 

# 해결방안

# 1. Batch Size

# 2. 페이징 처리 후 fetchJoin

저의 경우는 두번째 방법을 사용하여 해결하였습니다.

@Override
public List<Chatroom> search(Long roomId, String condition, LocalDateTime createdAt) {
    
	BooleanBuilder orBuilder = new BooleanBuilder()
		.or(titleContains(condition))
                .or(regionContains(condition))
                .or(tagContains(condition));

        List<Long> roomIds = queryFactory
            .select(chatroom.roomId)
            .from(chatroom)
            .leftJoin(chatroom.tags, tag)
            .where(
                orBuilder,
                cursorCondition(roomId, createdAt),
                statusEq(Status.ACTIVE)
            )
            .orderBy(
                chatroom.createdAt.desc(),
                chatroom.roomId.desc()
            )
            .limit(20)
            .fetch();

	return queryFactory
		.selectDistinct(chatroom)
		.from(chatroom)
		.leftJoin(chatroom.joins, join).fetchJoin()
		.where(
			chatroom.roomId.in(roomIds),
			joinStatusEq(Status.ACTIVE)
		)
		.orderBy(
			chatroom.createdAt.desc(),
			chatroom.roomId.desc()
		)
		.fetch();
}