🌐 페이지네이션의 필요성

하루에 약 8조 5천만 번의 검색 요청을 처리합니다.
만약 매 검색마다 서버가 모든 데이터를 한 번에 전송한다면 어떻게 될까요?
상상만 해도 끔찍한 일입니다.
이런 문제를 해결하기 위해 서버는 클라이언트가 요청한 데이터를 적절히 나눠서 전송하는 '페이지네이션'
기법을 사용합니다.

오늘은 두 가지 핵심 페이지네이션 방식을 자세히 살펴보겠습니다.

  1. 오프셋 페이지네이션(Offset Pagination)
  2. 커서 페이지네이션(Cursor Pagination)

각 방식의 장단점을 비교하고, 어떤 상황에서 어떤 방식이 더 적합한지 알아보겠습니다.

📚 오프셋 페이지네이션: 가장 직관적인 방식

개념 및 작동 원리

오프셋 페이지네이션은 데이터를 페이지 단위로 나눠서 조회하는 방식으로, '페이지 기반 페이지네이션'이라고도 불립니다. SQL에서는 LIMIT와 OFFSET 구문을 사용해 구현합니다.

SELECT * FROM table LIMIT 10 OFFSET 20
  • LIMIT: 한 페이지에 표시할 데이터 수를 지정합니다.
    위 예시에서는 10개의 데이터를 가져옵니다.
  • OFFSET: 몇 개의 데이터를 건너뛸지 지정합니다.
    위 예시에서는 처음 20개를 건너뛰고 그 다음부터 10개를 가져옵니다.

예를 들어, 페이지 당 10개의 데이터를 표시하는 경우

  • 1페이지: OFFSET 0, LIMIT 10 (처음부터 10개)
  • 2페이지: OFFSET 10, LIMIT 10 (11번째부터 10개)
  • 3페이지: OFFSET 20, LIMIT 10 (21번째부터 10개)

장점

  1. 구현이 간단하고 직관적: 가장 쉽게 구현할 수 있는 페이지네이션 방식입니다.
  2. 특정 페이지로 즉시 이동 가능: 원하는 페이지 번호만 알면 바로 해당 페이지로 이동할 수 있습니다.
  3. 전체 페이지 수 계산 용이: 전체 레코드 수를 알면 총 페이지 수를 쉽게 계산할 수 있습니다.

단점

  1. 성능 저하: 데이터가 많아질수록, 특히 뒤쪽 페이지로 갈수록 성능이 저하됩니다. 데이터베이스는 OFFSET만큼의 레코드를 스캔한 후 버려야 하기 때문입니다.
  2. 데이터 불일치 문제: 데이터 추가/삭제 시 일관성이 깨질 수 있습니다.

데이터 불일치 예시

1. 데이터 삭제 시

  • 클라이언트가 1페이지(1~10번)를 이미 로드한 상태
    누군가 9번 데이터를 삭제
  • 클라이언트가 2페이지를 요청하면 10개를 건너뛰고 조회하므로, 10번 데이터가 누락되고 11~20번 데이터를 받게 됨

2. 데이터 추가 시

  • 클라이언트가 1페이지(1~10번)를 이미 로드한 상태
  • 새로운 데이터(8.5번)가 8번과 9번 사이에 삽입됨
  • 클라이언트가 2페이지를 요청하면 10번 데이터가 중복으로 표시됨

이런 문제 때문에 무한 스크롤을 구현할 때 같은 데이터가 두 번 보이는 현상이 발생하기도 합니다.

🎯 커서 페이지네이션: 데이터 일관성의 해결책

개념 및 작동 원리

커서 페이지네이션은 '기준점'을 사용해 데이터를 조회하는 방식입니다.
단순히 몇 개를 건너뛰는 오프셋 방식과 달리, 커서 페이지네이션은 마지막으로 가져온 데이터를 기준으로 다음 데이터를 가져옵니다.

SELECT * FROM table WHERE id > 10 LIMIT 10

위 예시에서는 id > 10 조건이 핵심입니다.
마지막으로 본 레코드의 ID가 10이라면, 그 이후의 데이터를 조회하는 것입니다.

장점

  1. 데이터 일관성 유지: 데이터가 추가되거나 삭제되어도 일관성 있게 데이터를 조회할 수 있습니다.
  2. 일정한 성능: 데이터셋의 크기와 관계없이 일정한 성능을 보장합니다.
  3. 실시간 데이터 처리에 효과적: 실시간으로 변경되는 데이터를 다룰 때 특히 유용합니다.

단점

  1. 구현 난이도: 구현이 복잡하고 난이도가 높습니다.
  2. 불연속적 페이지 이동 제한: 이전/다음 페이지 이외의 임의 페이지로 이동하기 어렵습니다.
  3. 특별한 조건 필요
    • 커서로 사용되는 값은 유일(unique)해야 합니다.
    • 일정한 정렬이 가능한 조건(ordering)이 필요합니다.

복잡한 구현 예시

여러 필드를 기준으로 정렬할 경우, 튜플을 지원하는 DB에서는 비교적 간단하게 구현할 수 있습니다.

SELECT * FROM table WHERE (created_at, id) > ('2023-01-01', 100) LIMIT 10

하지만 튜플을 지원하지 않는 경우, 다음과 같이 풀어서 작성해야 합니다.

SELECT * FROM table 
WHERE created_at > '2023-01-01' 
   OR (created_at = '2023-01-01' AND id > 100) 
LIMIT 10

이런 경우 복잡도가 크게 증가하며, 애플리케이션 레벨에서의 추가 작업이 필요할 수 있습니다.

🤔 어떤 페이지네이션을 선택해야 할까?

페이지네이션 방식 선택은 애플리케이션의 특성과 요구사항에 따라 달라져야 합니다.

오프셋 페이지네이션이 적합한 경우

  • 전통적인 게시판: 페이지 번호를 클릭하여 이동하는 인터페이스
  • 구현 시간이 제한적인 경우: 빠르고 쉽게 구현해야 할 때
  • 데이터 변경이 빈번하지 않은 경우: 정적인 콘텐츠를 다룰 때

데이터 변경이 빈번하지 않은 경우: 정적인 콘텐츠를 다룰 때

커서 페이지네이션이 적합한 경우

  • 무한 스크롤: 스크롤을 내릴 때마다 데이터를 추가로 로드하는 인터페이스
  • 실시간 데이터 처리: 데이터가 자주 추가/삭제되는 경우
  • 대규모 데이터셋: 성능이 중요한 대용량 데이터를 다룰 때

📌 결론

페이지네이션은 대용량 데이터를 효율적으로 다루기 위한 필수 기술입니다.
오프셋 페이지네이션은 간단하고 직관적이지만 성능과 데이터 일관성 측면에서 한계가 있습니다.
반면, 커서 페이지네이션은 구현이 복잡하지만 데이터 일관성과 성능 면에서 우수합니다.
결국 "무조건 어떤 하나의 페이지네이션을 항상 사용하지 말고, 프로젝트와 상황에 맞게 적합한 페이지네이션 테크닉을 골라서 사용하는 것"이 중요합니다.

profile
에러가 나도 괜찮아 — 그건 내가 배우고 있다는 증거야.

0개의 댓글