[Querydsl] countQuery와 contentQuery 분리하기

황성현·2024년 2월 28일
0

Querydsl

목록 보기
1/1

1. 분리할 때의 장점?

  • count 쿼리를 분리함으로써 최적화 여지를 남길 수 있다
  • 예를들어 content 쿼리는 join을 여러번 걸고 조건이 복잡할 수 있으나, count 쿼리는 별개로 단순하게 구성될 수 있기에 분리함으로써 성능 개선을 도모할 수 있다.

2. 예제

@Override
public Page<MemberTeamDto> searchWithPaging(MemberSearchCond cond, Pageable pageable) {
    // 데이터 조회 쿼리 (페이징 적용)
    List<MemberTeamDto> content = queryFactory
            .select(
                    new QMemberTeamDto(
                            member.id,
                            member.username,
                            member.age,
                            team.id,
                            team.name
                    )
            )
            .from(member)
            .leftJoin(member.team, team)
            .where(
                    usernameEq(cond.getUsername()),
                    teamNameEq(cond.getTeamName()),
                    ageGoe(cond.getAgeGoe()),
                    ageLoe(cond.getAgeLoe())
            )
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();

    // count 쿼리 (조건에 부합하는 로우의 총 개수를 얻는 것이기 때문에 페이징 미적용)
    Long total = queryFactory
            .select(member.count()) // SQL 상으로는 count(member.id)와 동일
            .from(member)
            .leftJoin(member.team, team)
            .where(
                    usernameEq(cond.getUsername()),
                    teamNameEq(cond.getTeamName()),
                    ageGoe(cond.getAgeGoe()),
                    ageLoe(cond.getAgeLoe())
            )
            .fetchOne();

    return new PageImpl<>(content, pageable, total);
}

3. size()를 이용해서 countQuery?

long total = queryFactory
                .selectFrom(member)
                .leftJoin(member.team, team)
                .where(
                        usernameEq(cond.getUsername()),
                        teamNameEq(cond.getTeamName()),
                        ageGoe(cond.getAgeGoe()),
                        ageLoe(cond.getAgeLoe())
                )
                .fetch() // 조건에 부합하는 전체 데이터를 조회 (List)
                .size(); // List의 길이로 total을 구하기
  • count 함수는 SQL 차원에서 지원하기 때문에 굳이 이렇게 전체 데이터를 받아온 뒤에 애플리케이션 레벨에서 별도로 size()를 호출해서 구할 필요 없고, 처음부터 카운트 쿼리를 호출하는 것이 더 좋음. 그 이유는 전체 데이터를 불러오고 나서 size()로 구하는 방식은 관리하지 않을 내용을 영속성 컨텍스트에 모두 업로드한 후에 size()를 호출하기 때문에, 단순 count를 구하기 위해서 적절치 않음.

0개의 댓글