Spring Boot · 2026-04-28

Spring Boot 데이터베이스 페이징 성능 전략

Spring Boot 환경에서 대용량 데이터를 효율적으로 다루기 위한 페이징 전략과 성능 고려사항을 정리한 기술적 설계

작성일 : 2026-04-28 ㆍ 작성자 : 관리자
post
목차

개요

웹 애플리케이션에서 페이징은 응답 속도와 사용자 경험에 직접적인 영향을 준다. 특히 데이터가 커질수록 단순한 OFFSET 기반 페이징은 성능 저하를 유발한다. 이 글에서는 Spring Boot 환경을 기준으로 페이징 전략을 비교하고, JPA와 키셋(cursor) 페이징 구현 예, 운영 시 고려해야 할 성능 요인들을 정리한다.

페이징의 목적과 문제점

왜 페이징이 필요한가

대량의 레코드를 한 번에 반환하면 네트워크와 메모리 비용이 커진다. 따라서 필요한 만큼만 유저에게 전달하는 것이 핵심이다.

OFFSET 기반 페이징의 한계

  • OFFSET이 커질수록 DB는 스킵할 행을 스캔하므로 비용 증가
  • 동시성으로 인한 데이터 중복 또는 누락 가능성
  • count 쿼리의 비용이 높아 전체 페이지 수 계산이 부담스러움

페이징 전략 비교

LIMIT / OFFSET

간단하고 구현이 쉽다. 작은 오프셋에서는 문제없다. 그러나 대형 데이터셋에서는 성능 저하가 심하다.

키셋(Cursor) 페이징

정렬 기준의 마지막 키를 기준으로 다음 페이지를 조회한다. DB는 인덱스를 사용해 빠르게 탐색할 수 있다. 대규모 목록 조회에 적합하다.

비교 요약

  • OFFSET: 구현 용이성 높음, 큰 오프셋에서 비효율
  • Cursor(키셋): 일관된 응답시간, 특정 정렬에 의존
  • 복합 전략: 초기 페이지는 OFFSET, 심화 조회는 키셋 병용 가능

Spring Boot 적용 방법

JPA 기본 페이징

Spring Data JPA는 Pageable과 Page를 제공한다. 간단한 목록에서는 빠르게 적용 가능하다.

public interface UserRepository extends JpaRepository<User, Long> {
    Page<User> findAll(Pageable pageable);
}

Controller에서는 Pageable을 받아 Page<User>를 반환한다. 다만 내부적으로 OFFSET을 사용하므로 대용량에서는 주의가 필요하다.

키셋 페이징 구현 예

키셋 페이징은 마지막 항목의 키를 전달받아 이후 데이터를 조회한다. 인덱스가 존재하면 성능이 좋다.

@Query("SELECT u FROM User u WHERE u.id < :lastId ORDER BY u.id DESC")
List<User> findByIdLessThanOrderByIdDesc(@Param("lastId") Long lastId, Pageable pageable);

// SQL 예시
SELECT * FROM users WHERE id < :lastId ORDER BY id DESC LIMIT :size;

프론트엔드는 각 페이지 응답에 마지막 ID를 포함한다. 다음 요청은 그 ID를 전달한다.

페이징 토큰 사용

마지막 키를 그대로 쓰면 안전하지 않은 경우가 있다. 이때 암호화된 페이징 토큰을 사용하면 무결성과 사용 편의성을 확보할 수 있다.

성능 고려사항

인덱스 설계

  • 정렬과 검색에 사용되는 컬럼에 적절한 인덱스 적용
  • 복합 정렬의 경우 복합 인덱스 검토

select 절 최적화

불필요한 컬럼 조회를 피한다. 필요한 컬럼만 DTO로 프로젝션하면 IO와 메모리 비용을 줄일 수 있다.

count 쿼리 대체 방안

전체 페이지 수가 비용이 클 때는 정확한 count 대신 '다음 페이지 존재 여부' 플래그로 대체한다. 또는 추정 카운트를 사용한다.

JPA 관련 주의

  • fetch join 사용 시 페이징이 메모리로 로드되는 경우 주의
  • 데이터 변환은 DB 조회 후 가능한 한 지연 처리
  • N+1 문제는 EntityGraph나 join fetch, 또는 DTO 조회로 해결

모니터링과 테스트

실제 워크로드로 부하 테스트를 수행한다. EXPLAIN이나 실행계획을 확인해 병목을 찾는다. 지연 시간이 목표치를 벗어나면 쿼리와 인덱스를 재검토한다.

  • 로드 테스트 도구로 다양한 오프셋과 키셋 시나리오 검증
  • 프로파일링으로 GC, 메모리, 네트워크 병목 확인

결론

페이징 전략은 단일 해법이 없다. 소규모 데이터와 단순 페이지 네비게이션은 JPA의 Pageable로 충분하다. 반면 대규모 리스트나 깊은 페이지 접근이 잦은 서비스는 키셋(cursor) 페이징이 더 적합하다. 인덱스, 선택적 컬럼 조회, count 쿼리 대체, 그리고 적절한 모니터링이 함께해야 안정적 성능을 달성할 수 있다.

spring boot 페이징 성능 jpa 페이징 최적화 cursor pagination spring boot 키셋 페이징 오프셋 페이징 데이터베이스 성능 쿼리 최적화 인덱스 설계