← 전체 글로 돌아가기

API

목록 API 페이지네이션에서 offset과 cursor를 고른 비교 메모

새 글이 계속 추가되는 목록에서 offset 방식이 만든 중복을 보고 cursor 기준으로 바꾼 비교 메모입니다.

두 번째 페이지에 같은 글이 보였다

관리자 목록을 offset=20으로 만들었을 때, 첫 페이지를 본 뒤 새 글이 올라오면 두 번째 페이지 첫 항목이 겹쳤습니다. 데이터가 틀린 것이 아니라 위치를 기준으로 잘라 낸 결과였습니다.

offset이 잘 맞는 자리

페이지 번호로 바로 이동하는 내부 목록, 데이터 변화가 적은 화면에서는 offset이 읽기 쉽습니다.

SELECT id, title
FROM posts
ORDER BY created_at DESC
LIMIT 20 OFFSET 40;

다만 큰 offset은 앞 행을 건너뛰는 비용이 커질 수 있고 삽입과 삭제가 많은 피드에는 안정적이지 않습니다.

피드에는 cursor를 넘겼다

공개 피드는 마지막 항목의 created_atid를 cursor로 인코딩했습니다. 시간이 같은 글도 있으므로 날짜 하나만 비교하지 않은 것이 수정 기준입니다.

SELECT id, title, created_at
FROM posts
WHERE (created_at, id) < ($1, $2)
ORDER BY created_at DESC, id DESC
LIMIT 21;

21개를 가져와 20개만 보여 주면 다음 페이지 유무도 알 수 있습니다. cursor는 URL에 노출되므로 base64는 숨김 기능이 아니라 형식 변환일 뿐입니다.

선택 체크

  • 임의의 57페이지로 이동해야 하면 offset을 검토한다.
  • 최신 항목이 계속 들어오는 피드면 cursor를 우선한다.
  • 정렬 컬럼과 보조 id에 인덱스가 있는지 확인한다.

한 API에 두 방식을 억지로 섞기보다 화면의 이동 방식부터 정한 뒤 쿼리를 정하니 설명도 테스트도 쉬웠습니다.