페이징 전략 정리 (실무 중심)

✅ 1. 기본 페이징: from + size

🔹 개념

SQL의 OFFSET, LIMIT처럼 특정 위치부터 몇 개를 가져옴.

{
  "query": { "match_all": {} },
  "from": 0,
  "size": 10
}

✅ 특징

  • 가장 기본적인 방법
  • from=0, size=10 → 1페이지, from=10, size=10 → 2페이지

⚠️ 주의사항

  • from이 클수록 성능이 나빠짐 (deep pagination)
  • 기본 최대는 10,000 (index.max_result_window 초과 시 에러)

💡 실무 팁

  • 리스트 조회에는 적합
  • 대용량 페이징에는 search_after 또는 scroll 사용

✅ 2. 안정적인 순차 페이징: search_after

🔹 개념

정렬된 필드 기준으로 커서를 넘겨 다음 페이지 요청

{
  "query": { "match_all": {} },
  "size": 10,
  "sort": [{ "created_at": "desc" }, { "_id": "desc" }],
  "search_after": ["2024-01-01T00:00:00", "abc123"]
}

✅ 특징

  • sort 필수
  • search_after는 이전 문서의 마지막 sort 값

⚠️ 주의사항

  • from과 병행 불가
  • 정렬 필드는 고유한 값 포함 필요 (예: created_at + _id)

💡 실무 팁

  • 무한 스크롤 또는 next 버튼 기반 페이지에 적합
  • 실시간 데이터 변동에도 일관성 유지

✅ 3. 대용량 전체 조회: scroll

🔹 개념

scroll context를 유지하면서 반복적으로 대량 조회

{
  "scroll": "1m",
  "size": 100,
  "query": { "match_all": {} }
}

✅ 특징

  • 정렬 없이 사용 가능
  • 전체 데이터를 순차적으로 조회

⚠️ 주의사항

  • 실시간성 없음 (스냅샷 기반)
  • 메모리 리스크 → 오래 유지 ❌

💡 실무 팁

  • 백업, ETL, 로그 수집 등에 사용
  • UI 페이징에는 적합하지 않음

✅ 4. 최신 방식: Point In Time (PIT) + search_after

🔹 개념

스냅샷 기준으로 안정적인 페이징 제공 (8.x 이상)

// PIT 열기
POST /my-index/_pit?keep_alive=1m

// PIT 기반 search
{
  "size": 10,
  "query": { "match_all": {} },
  "pit": { "id": "<PIT_ID>", "keep_alive": "1m" },
  "sort": [{ "created_at": "desc" }, { "_shard_doc": "desc" }]
}

✅ 특징

  • PIT 유지하며 search_after 사용
  • 동일한 기준으로 정확한 페이징 가능

💡 실무 팁

  • 정밀하고 정확한 페이지 조회 필요할 때 사용
  • 사용 후 close 권장

✅ 페이징 전략 비교표

전략장점단점사용 시점
from + size구현 쉬움deep pagination 시 성능 저하소규모 조회
search_after커서 방식, 빠름중간 페이지 이동 불가무한 스크롤 등
scroll전체 조회실시간성 없음, 리소스 큼백업, 배치 처리
PIT + search_after정확도 최고, 최신 방식8.x 이상, 관리 필요고정된 검색 기준 페이징