헤르메스 LIFE

[Spring Boot] Spring Data JPA에서 GroupBy 처리하기 본문

Spring Boot Framework

[Spring Boot] Spring Data JPA에서 GroupBy 처리하기

헤르메스의날개 2023. 2. 26. 21:47
728x90

제가 궁금한 모든 예제.

감사합니다.

출처 : https://medium.com/@odysseymoon/spring-data-jpa%EC%97%90%EC%84%9C-groupby-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-82cddc6e5d4a

 

Spring Data JPA에서 GroupBy 처리하기

Spring Data JPA에서는 GroupBy 를 사용하려면 어떻게 해야 할까요? Reference Doc 에서도 Group By 관련 키워드는 찾아보기 힘듭니다. Group By를 이용하려면 다른 방식을 적용해야 하는데요, Spring…

medium.com


Spring Data JPA에서는 GroupBy 를 사용하려면 어떻게 해야 할까요? Reference Doc 에서도 Group By 관련 키워드는 찾아보기 힘듭니다. Group By를 이용하려면 다른 방식을 적용해야 하는데요, Spring Data JPA에서 Group By를 사용하기 위한 4가지 방식에 대해 알아보겠습니다.

Conditions

일단 Database Table이 다음과 같이 정의 되어 있다고 가정할 때

 

Entity 를 다음과 같이 생성합니다.

 

report 테이블에서 year 별로 Report 엔티티의 각 합산값을 구해보겠습니다.

사용법

Java8 Stream 활용

순수 Application 단에서 Java 8의 Stream을 이용해 Entity 를 Group By 할 수 있습니다.

 

Java8에 collect 를 이용하면 다양한 groupBy를 사용할 수 있습니다.
위 예제에서는 sum 값을 구하는 필드가 한 개 이상이기 때문에 Collectors.toMap 을 이용하여 Report.getYear() 를 기준으로 YearReportSum 을 생성하는 방식으로 사용하였습니다.

Java8 Stream을 사용하게 되면 어플리케이션 단에서 구현된 내용을 쉽게 수정하거나 파악할 수 있는 장점이 있지만 전체 Data를 어플리케이션에서 group by 를 하기 때문에 데이터가 많아지면 많아질 수 록 속도가 느려지고 메모리를 많이 사용하게 됩니다. 적은 데이터에 대해 빠른 구현으로는 적합하지만 많은 데이터에 대해서는 적절한 방식은 아닙니다.

JPQL 활용

JPA에 JPQL  Projection 을 이용해서 Entity가 아닌 DTO에 Query 결과값을 담을 수 있습니다.

 

JPQL 을 이용하면 Query에 대한 타입 안정성과 Query 안정성을 바로 확인 할 수 있지만 Projection 을 사용할 때 new 를 통해 생성자를 쿼리 내에서 호출해줘야 해서 Query가 장황해지는 단점이 있습니다.

Native Query 활용

Native Query에 대해 Entity 가 아닌 Return값을 반환받기 위해서는 Interface based Projection 을 활용해야 합니다.

Interface 를 다음과 같이 선언합니다.

public interface YearReportSumInterface {

    Integer getYear();
    BigDecimal getSmallSum();
    BigDecimal getMajorSum();
    BigDecimal getTotalSum();

}

선언된 Interface 에 맞게 Native Query를 작성합니다.

 

JPQL 과 유사하지만 nativeQuery=true 를 통해 순수 Query로 작성되어 있으며, Select된 각 컬럼을 Interface 명에 맞춰 Alias를 설정해 줘야 합니다.

Native Query 를 활용하게 되면 쿼리 자체를 Database에서 빠르게 검증 가능하지만, 반환된 Interface 를 별도의 DTO로 변환해야 할 필요성이 생깁니다.

QueryDSL 활용

QueryDSL 을 활용한 Group By 쿼리는 JPAQuery 를 직접 활용해야 합니다.

 

QueryDSL 에서 Group By 를 사용하기 위해서는 EntityManager 를 통해 JPAQuery 를 직접 생성해서 사용해야 하는 단점이 있지만, QueryDSL 의 장점인 다양한 조건의 쿼리를 생성할 수 있다는 장점이 있습니다. ( Optional 한 쿼리 조건을 각각 적용 가능)

성능

간단하게 local에서 약 230건의 데이터에 대해 각각 100회씩 호출 하였을 경우 API 응답 시간 성능 측정 결과는 아래와 같았습니다.
(개별 환경에 따라 다를 수 있습니다)

결과에서 보는 것과 같이 Java8 Stream이 가장 속도가 느리며 나머지는 실제 쿼리가 비슷하기 때문에 평균 응답시간도 같게 나왔습니다.

다만 JPQL과 QueryDSL은 초기 쿼리 파싱 때문에 Max 속도가 다른것을 볼 수 있습니다.

728x90