Pagination의 offset 방식과 no-offset 방식

파이 ఇ·2024년 11월 3일
0
post-thumbnail

📌 Pagination을 사용하는 이유?

100만개의 상품이 있는 애플리케이션에서 사용자가 상품의 목록을 요청한다고 가정해보자. 매번 100만개의 데이터를 전부 가져오게되면 매우 느려지며 사용자는 불편함을 느끼게 될 것이다. 하지만 데이터를 조금씩 (20~100개) 나눠서 가져오고 사용자가 원하는 경우 다음 데이터를 가져오게 되면 훨씬 빠르고 사용자도 애플리케이션에 대해 만족할 것이다. 이러한 이유로 Pagination을 사용한다.

Pagination 구현 방법

  • offset 방식 : offset과 limit 예약어를 통해 select의 전체 결과 중 일부만 가져오는 방법이다.
  • no-offset(cursor) 방식 : cursor는 어떠한 row를 가르키는 포인터이고, 이 cursor가 가르키는 row부터 일정 개수만큼 데이터를 가져오는 방식이다.

📌 offset

offset이란 SQL에서 조회를 시작할 기준점을 의미하고 limit는 조회할 결과의 개수를 의미한다.

SELECT * FROM { 테이블 이름 } LIMIT 20 OFFSET 60;

위와 같은 예시는 60번째 행부터 20개의 데이터를 읽겠다는 것을 의미한다. (이때 행은 0부터 시작) offset은 조회를 한 결과에서 limit로 지정한 개수만큼만 반환하고 나머지는 버리는 식으로 동작한다.
위 쿼리로 예를 들자면 60번째 row부터 20개를 조회하기 위해서 80개의 데이터(row의 0부터 79번째 까지)를 모두 읽은 뒤, 앞의 필요없는 60개의 데이터는 버려야 한다.
위 쿼리처럼 적은양의 데이터를 조회할 때는 성능적인 문제가 발생하지 않지만, 전체 데이터의 개수가 많아질수록 버려지는 데이터의 양이 많아져 문제가 된다.

offset 방식의 장점

  • 직관적인 코드
    기본적인 SELECT ... OFFSET X LIMIT Y 구조로 간단히 구현할 수 있어 코드가 직관적이다. 다양한 검색 조건을 추가해도 구조 자체는 동일해, 쿼리 작성이 비교적 간편하다.
  • 유연한 페이지 접근
    검색 조건이 다양해질 경우 에도 OFFSETLIMIT만 수정하면 되므로, 복잡한 필터나 검색 조건이 적용되는 경우에도 적용이 쉽다.

offset 방식의 단점

  • 성능 저하
    위에서 말했듯이 offset 방식은 여러 개의 데이터를 한꺼번에 가져와 필요한 만큼만 출력하고 나머지는 버려지게 된다. 예를 들어 1,000,000개의 데이터를 가지고있고, 100,000번째의 row에서 20개만 필요하다고 가정해보자. 내가 필요한 만큼은 20개인데 데이터는 100,020개를 가져오고 100,000개의 불필요한 데이터가 버려지게된다. 그 숫자는 커지면 커질수록 속도는 저하된다.

  • 비효율적인 인덱스 활용
    offset 방식은 인덱스 활용도가 낮고, 큰 페이지 번호로 이동할수록 인덱스 스캔 비용이 증가해 쿼리 성능에 영향을 미친다.

    • offset이 큰 값일 때는 인덱스를 사용하더라도 많은 데이터 스캔이 필요하므로 인덱스에 대한 효율성이 떨어진다.
  • 데이터 일관성 문제
    실시간으로 데이터가 변동되는 경우, offset 방식은 페이지 간 이동 시 일관성을 보장하기 어려울 수 있다. 특히 데이터가 추가, 삭제가 빈번한 상황에서는 중복 조회나 데이터 누락이 발생할 수 있다.

    • 예를 들어, 사용자가 1페이지의 1번부터 5번까지의 상품을 보고있는데 관리자가 4,5번 상품을 삭제했다고 가정하고, 사용자는 상품의 2페이지를 요청한다고 가정할 시 데이터베이스는
      나는 1번부터 5개를 줬는.. 어? 4번 5번이 없네? 그럼 7번까지 줬구나 !
      라고 생각하고 2페이지는 8번 상품부터 5개의 데이터를 보내줄것이다. 그 결과 6번상품과 7번상품의 데이터가 누락이 된다.

📌 no-offset(cursor)

no-offset(=cursor) 방식은 이 전 페이지의 마지막 데이터의 id 값을 기억하고, 다음 페이지를 요청할 때 이 id 값 이후의 데이터를 가져오는 방식이다.
이를 통해 매번 offset 값을 계산하지 않아도 되기 때문에 데이터베이스에서 더욱 효율적으로 데이터를 가져올 수 있다.
이 방식을 사용할 경우 기준점 이전의 데이터도 모두 조회하던 offset 방식과는 달리 기준점(=cursor)부터 limit의 개수만 조회하기 때문에 데이터의 개수가 많아져도 성능 문제가 발생하지 않는다.
보통 무한 스크롤이라 칭하기도 하고, sns에서 많이 사용되고 있다.

SELECT * FROM { 테이블 }
WHERE { 조건문 }
AND id < lastId
ORDER BY id DESC 
LIMIT { 컨텐츠 개수 }

no-offset(cursor)방식의 장점

  • 성능 최적화
    특정 인덱스를 기준으로 데이터를 조회하여, offset 방식과 달리 필요하지 않은 데이터 스캔이 줄어들어 성능이 빠르게 동작한다. 특히 대용량 데이터에서도 높은 성능을 유지할 수 있다.
  • 데이터 일관성 유지
    고유 ID나 타임스탬프를 기준으로 조회하면 데이터가 변경되더라도 이전에 조회한 결과와 일관성을 유지하기가 용이하다. 이를 통해 페이지 이동 중 데이터의 순서가 안정적으로 유지된다.

no-offset(cursor)방식의 단점

  • 검색 조건 추가 시 한계
    • no-offset방식은 주로 단일 키(고유 ID, 타임스탬프)를 기준으로 하기 때문에 검색 조건이 많아질 경우 특정 인덱스를 기반으로 데이터를 잘라내기 어렵다. 예를 들어, 필터가 여러 개 적용되는 경우 인덱스 필드 기준으로 페이지를 정하기가 복잡해지며, 특정 인덱스가 모든 조건에 적합하지 않아 성능 저하가 발생할 수 있다.
    • 복합 조건에 따라 유동적인 정렬 순서를 요구하는 경우, 고유 키로 페이지를 구분하는 방식이 불가능해질 수 있다. 이 때문에 다양한 필터링을 필요로 하는 경우에는 구조적 한계가 있다.
  • 임의 페이지 이동의 어려움
    특정 위치에서 이어서 조회하는 방식이기 때문에, 사용자 요청에 따라 임의의 페이지 번호로 바로 이동하기 어렵다. (ex. 1페이지에서 5페이지로 바로 이동). 원하는 위치로 이동하기 위해서는 차례로 페이지를 조회하는 방법 외에는 대안이 없다.
  • 구현 복잡성
    pagination구현 시 각 페이지의 마지막 ID를 기준으로 다음 페이지를 조회해야 하기 때문에 코드가 복잡해진다. 다양한 검색 조건을 추가하는 경우 이러한 기준을 설정하는 로직이 복잡해지며, 유지보수에 어려움을 겪을 수 있다.

요약

복합적인 검색 조건이 필요하거나 다양한 필터링을 제공해야 하는 경우라면 offset 방식이 유연하게 대응할 수 있다. 반면, 특정 키나 필드를 중심으로 일관된 순서를 유지하면서 빠르게 pagination을 제공해야 한다면 no-offset 방식이 적합하다.

즉, 각각의 장 단점을 살펴보고 상황에 맞게 적용하는게 best!

끝!

profile
⋆。゚★⋆⁺₊⋆ ゚☾ ゚。⋆ ☁︎。₊⋆

0개의 댓글