← 전체 글로 돌아가기

DB

DB 페이지네이션 쿼리에서 오프셋 계산 확인하기

페이지네이션 쿼리가 중복된 데이터를 반환하거나 데이터를 빠뜨린다면, 먼저 쿼리 자체를 직접 실행해서 결과를 확인해야 한다.

페이지네이션 쿼리에서 데이터가 중복되거나 빠지는 문제는 대부분 오프셋과 리미트 계산이 잘못됐거나, 정렬 기준이 없어서다.

페이지네이션 쿼리의 기본

Prisma에서 기본적인 페이지네이션은 이렇게 한다:

const page = 1;
const pageSize = 10;
const skip = (page - 1) * pageSize;

const items = await prisma.item.findMany({
  skip,
  take: pageSize,
  orderBy: { id: 'asc' }
});

중요한 건 반드시 정렬 기준을 명시하는 것이다. 정렬 기준이 없으면 DB가 매번 다른 순서로 반환할 수 있다.

쿼리가 맞는지 확인하기

Prisma에서 실제 어떤 SQL이 실행되는지 보려면:

echo "console.log(Prisma.sql`...query...`)" | node

또는 로그를 켜서 본다:

const prisma = new PrismaClient({
  log: ['query', 'info']
});

데이터 누락이나 중복 있을 때

  1. 정렬 기준 확인: 같은 값을 가진 행들이 있으면 페이지마다 순서가 바뀔 수 있다. id 같은 고유 값으로 이차 정렬을 추가한다.
orderBy: [{ createdAt: 'desc' }, { id: 'desc' }]
  1. skip/take 값 확인: 페이지 번호 계산이 0 기반인지 1 기반인지 명확히 한다.

  2. 삭제된 데이터: 페이지 조회 중에 데이터가 삭제되면 오프셋이 밀린다. 최근 데이터 기준으로 커서 기반 페이지네이션을 고려하자.

커서 기반 페이지네이션이 더 안전한 이유

오프셋 기반보다 커서 기반이 더 안정적이다:

const items = await prisma.item.findMany({
  take: pageSize + 1,
  skip: cursor ? 1 : 0,
  cursor: cursor ? { id: cursor } : undefined,
  orderBy: { id: 'desc' }
});

DB 크기가 커질수록 커서 기반 방식이 훨씬 빠르고 안정적이다.