ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • QueryDSL fetchCount() deprecated 대안
    JPA 2022. 12. 7. 00:01
    728x90

    개요

    Querydsl의 이전 버전에서는 fetchResults(), fetchCount() 메서드를 이용하여 페이징 쿼리를 작성했지만 5.0.0 버전에서 deprecated 되었습니다.

     

    deprecated란?

    일반적으로 위험하거나 더 나은 대안이 있기 때문에 프로그래머가 사용하지 않는 것이 좋습니다.

    호환되지 않게 변경되거나 향후 버전에서 제거될 수 있습니다.

     

    이유는 다음과 같습니다.

    fetchResults() : Get the projection in QueryResults form. Make sure to use fetch() instead if you do not rely on the QueryResults.getOffset() or QueryResults.getLimit(), because it will be more performant. Also, count queries cannot be properly generated for all dialects. For example: in JPA count queries can’t be generated for queries that have multiple group by expressions or a having clause. Get the projection in QueryResults form. Use fetch() instead if you do not need the total count of rows in the query result.

     

    요약하자면 모든 dialects에 대해 count query를 올바르게 생성할 수 없습니다.

    예를 들면 JPA에서 여러개의 group by 표현식이나 , having 절이 있는 query에 대해 count query를 생성할 수 없습니다.

     

    fetchCount() : An implementation is allowed to fall back to fetch().size().

    fetchCount() 대신 fetch().size()로 동일한 결과를 얻을 수 있습니다.

     

    예시)

    int totalSize = queryFactory // count 쿼리
                            .selectFrom(user)
                            .where(user.username.like("user_"))
                            .fetch().size();

     

    하지만 반환 값이 int입니다.

    서비스의 데이터의 크기에 고려하여 적합하게 사용해야 합니다 (overflow 주의)

     

     

    Deprecated된 fetchCount

     

    fetch().size() 이외에 Long 타입을 사용하고 싶은 경우에 다음과 같은 방법을 사용할 수 있습니다.

    Long count = queryFactory.select(member.count())
                             .from(member)
                             .fetchOne();
    • member.count() 를 사용하면 count(member.id) 로 처리된다.
    • count(*) 로 처리하고 싶으면 Wildcard.count 를 사용하면 된다.
    • 응답 결과는 숫자 하나이므로 fetchOne() 을 사용한다.

     

    Wildcard.count 사용

    Long count = queryFactory.select(Wildcard.count)
                             .from(member)
                             .fetchOne();

     

    주요 시간복잡도

    ArrayList.size()의 시간복잡도는 O(1) 입니다.

    MyISAM : 각 row 수가 각 테이블에 저장되어 count(*)는 O(1)의 시간복잡도

    InnoDB : full scan으로 시간복잡도 O(N)

    PostgreSQL : Seq Scan으로 시간복잡도 O(N)

     

    데이터가 쌓여가면서 느려질 수 있는 count query

    • 이때 트리거를 등을 통하여 count 수를 따로 관리해준다면 count query를 빠르게 관리할 수 있을 것 같습니다.

     

     

    PostgreSQL 카운트 쿼리에 주의해야 할 점

    위의 테이블에서 contents에 내용이 있는 것들의 개수를 알아보기 위해 COUNT를 사용하며 이때 결과로 6을 원하지만 8이 응답됩니다.

    COUNT는 NULL이 아닌 Column을 모두 합하기 때문에 공백에 주의해야 합니다.

    'JPA' 카테고리의 다른 글

    QueryDSL StringTemplate이란?  (0) 2023.02.03
    QueryDSL이란?  (0) 2023.02.01
    동적쿼리란? with Querydsl  (0) 2022.09.07
    OSIV란?  (0) 2022.08.16
    JPA란? (+ORM이란?)  (0) 2022.04.04

    댓글

Designed by Tistory.