Using Sort, Scrolling Large Query Results

2024. 10. 20. 18:59Spring Boot/Spring Data JPA

Using Sort

Spring Data JPA에서 정렬(Sort)은 PageRequest를 제공하거나 직접 Sort 객체를 사용하여 수행할 수 있습니다. 이때, 사용되는 정렬 속성은 도메인 모델에 맞아야 하며, 쿼리 내에서 사용되는 속성이나 별칭과 일치해야 합니다. JPQL에서는 이를 상태 필드 경로 표현(state field path expression)이라고 정의합니다.

아래는 정렬과 JpaSort를 사용하는 방법을 상세히 설명한 내용입니다.

1. Sort 사용

Sort 객체는 쿼리에 전달되어 결과를 정렬하는 데 사용됩니다. Sort를 사용하여 정렬할 때는 도메인 모델에서 사용되는 속성명을 기반으로 정렬 기준을 설정해야 합니다. 잘못된 경로 표현을 사용하면 예외가 발생합니다.

다음은 정렬과 JPQL 쿼리를 사용하는 예입니다:

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("select u from User u where u.lastname like ?1%")
    List<User> findByAndSort(String lastname, Sort sort);

    @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
    List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
}

2. 정렬 예제

아래는 findByAndSort 메서드를 호출하여 정렬하는 예입니다:

repo.findByAndSort("lannister", Sort.by("firstname"));               // (1)
repo.findByAndSort("stark", Sort.by("LENGTH(firstname)"));          // (2)
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); // (3)
repo.findByAsArrayAndSort("bolton", Sort.by("fn_len"));             // (4)

각 호출에 대한 설명:

  1. (1): 도메인 모델의 속성인 firstname을 사용한 유효한 정렬입니다.
  2. (2): 함수 호출인 LENGTH(firstname)을 사용했으므로 예외가 발생합니다. 이는 JPQL에서 허용되지 않는 정렬입니다.
  3. (3): JpaSort.unsafe를 사용하여 명시적으로 안전하지 않은 정렬을 지정했습니다. 이 경우 함수 호출을 포함한 정렬이 허용됩니다.
  4. (4): 쿼리에서 정의된 별칭 fn_len을 사용하여 유효한 정렬입니다. 이 쿼리는 LENGTH(u.firstname)의 결과를 fn_len으로 alias하고 이를 통해 정렬합니다.

3. JpaSort와 안전하지 않은 정렬

기본적으로 Spring Data JPA는 함수 호출을 포함한 정렬 인스턴스를 거부합니다. 그러나 JpaSort.unsafe를 사용하면 이러한 잠재적으로 안전하지 않은 정렬을 추가할 수 있습니다. 이는 쿼리 문자열에 정렬 조건이 추가되기 때문에 가능합니다.

 

정렬을 사용할 때는 도메인 모델의 속성 또는 쿼리에서 정의된 별칭을 기반으로 하는 것이 중요합니다. JpaSort.unsafe를 사용하면 보다 유연한 정렬이 가능하지만, 이 경우 SQL 인젝션과 같은 보안 문제에 유의해야 합니다. 이를 통해 Spring Data JPA의 강력한 쿼리 작성 능력을 더욱 확장할 수 있습니다.

Scrolling Large Query Results

대규모 데이터 세트를 다룰 때, 스크롤링(Scrolling)은 모든 결과를 메모리에 로드하지 않고 효율적으로 처리하는 데 도움을 줄 수 있습니다. 아래에서는 대규모 쿼리 결과를 소비하기 위한 여러 가지 옵션에 대해 자세히 설명하겠습니다.

1. 스크롤링 방식

데이터베이스에서 대량의 결과를 처리할 때 사용할 수 있는 스크롤링 방법은 다음과 같습니다:

1.1 Paging (페이지네이션)

  • 페이지네이션은 이미 익숙한 방법으로, PageablePageRequest를 사용하여 결과를 페이지 단위로 나누어 조회합니다. 이는 총 결과 수를 계산하고, 사용자가 요청한 특정 페이지에 해당하는 데이터만을 가져오는 방식입니다.

1.2 Offset-based Scrolling (오프셋 기반 스크롤링)

  • 오프셋 기반 스크롤링은 페이지네이션의 경량화된 버전입니다. 이 방식은 전체 결과 수를 요구하지 않으며, 사용자가 특정 위치에서부터 데이터를 가져오는 방식입니다.
  • 예를 들어, 첫 번째 100개의 결과를 가져온 후, 다음 100개를 가져오고 싶을 때 사용할 수 있습니다. 그러나 이 방법은 데이터가 추가되거나 삭제될 경우, 결과가 불안정해질 수 있습니다.

1.3 Keyset-based Scrolling (키셋 기반 스크롤링)

  • 키셋 기반 스크롤링은 오프셋 기반 스크롤링의 단점을 피하는 방법입니다. 데이터베이스 인덱스를 활용하여 더 효율적으로 결과를 검색합니다.
  • 이 방식은 페이지가 변경될 때 결과가 안정적이며, 특히 고유한 키가 있는 데이터에 대해 성능을 극대화할 수 있습니다.

2. 사용 가능한 API

스크롤링을 구현하는 데 사용할 수 있는 다양한 API가 있습니다.

  • Scroll API: 쿼리 메서드, Query-by-Example, Querydsl과 함께 사용할 수 있습니다. 이를 통해 대량의 데이터를 단계적으로 처리할 수 있습니다.

3. 제한 사항

  • 문자열 기반 쿼리 메서드를 사용한 스크롤링은 현재 지원되지 않으며, 저장된 @Procedure 쿼리 메서드를 사용하는 경우에도 스크롤링이 지원되지 않습니다. 이는 성능과 안정성을 보장하기 위한 제한 사항입니다.


대규모 데이터 세트를 처리할 때 스크롤링을 통해 메모리 사용을 최적화할 수 있으며, 다양한 방법과 API를 활용하여 요구 사항에 맞는 최적의 접근 방식을 선택할 수 있습니다. 각 스크롤링 방식의 특징과 한계를 이해하고 적절하게 활용하는 것이 중요합니다.

'Spring Boot > Spring Data JPA' 카테고리의 다른 글

Applying Query Hints  (0) 2024.10.20
Other Methods, Modifying Queries  (0) 2024.10.20
Using @Query  (0) 2024.10.20
Using JPA Named Queries  (0) 2024.10.20
Query Lookup Strategies  (0) 2024.10.20