커서 기반 페이지네이션

오민석·2021년 5월 10일
1

페이지네이션 방법

오프셋 기반 페이지네이션 (Offset-based Pagination)
DB의 offset 쿼리를 사용하여 '페이지' 단위로 구분하여 요청/응답하게 구현

커서 기반 페이지네이션 (Cursor-based Pagination)
클라이언트가 가져간 마지막 row의 순서상 다음 row들을 n개 요청/응답하게 구현텍스트

오프셋 기반 페이지네이션 (Offset-based Pagination)

전체 데이터에서 offset부터 limit까지만 데이터를 가져오는 방식이다.
select * from post LIMIT 0,5

/user1/post?page=1&pageSize=5
page=1이 몇 번째 부터 데이터를 가져올건지,pageSize=5는 offset부터 몇 개의 데이터 가져올건지다. select할 때 LIMIT start,end에 대응하는 값이다.

단점

  • 예를 들어 유저가 1페이지를 요청하여 5개의 아이템을 돌려준 상황을 가정하자. 그리고 30분쯤 후에 유저가 2페이지를 요청한다고 할 때, 만약 그 사이에 3개의 새로운 아이템이 추가된다면 2개의 아이템이 중복으로 전송된 셈이 된다.

  • SNS를 통한 CUD 작업이 많아짐에 따라 커서 기반 페이지네이션 (Cursor-based Pagination) 필요해졌다.

커서 기반 페이지네이션 (Cursor-based Pagination)

SNS와 같은 실시간, 대량의 데이터에서 사용되는 방식으로 무한 스크롤 방식에서 사용된다.

각 엔터티에 고유한 커서 값을 할당하고, 기준 커서값과 사이즈로 다음 페이지를 가져오는 방식이다. 중간에 새로운 데이터가 들어오더라도, 그 데이터 다음에서 몇 건 기준으로 가져오기때문에 중복된 데이터 없이 항상 새로운 데이터만 가져온다.

TypeGraphQL에서는 다음과 같이 페이지네이션을 구현한다. first는 몇 개의 데이터를 가져올건지 limit을 뜻하고, after는 마지막 항목 index다. 커서는 connection을 위해 존재하는 것임으로 Post 타입에 존재하는건 좋지 않기 때문에, 간접 지정을 위해 새로운 layer을 지정한다. edge는 하위 node와 cursor를 반환하도록 한다.

추가로 connection이 언제 끝났는지 알 기 위해(빈 배열을 받을 때까지 계속 쿼리 지양) pageInfo 객체를 추가하여 endCursor, hasNextPage를 포함한다. endCursor을 기반으로 새로운 요청 할 수 있고, 다음 페이지가 없다면 hasNextPage는 false를 반환한다.

쿼리

query {
  getMyPosts(first: 3, postType: Answer, after: "6") {
    edges {
      node {
        id,
        content,
        postType,
        usedEmoticons {
          id
          positionX
          positionY
          emoticon {
            id,
            fileUrl
          }
        }
      }
      cursor
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}

결과

{
  "data": {
    "getMyPosts": {
      "edges": [
        {
          "node": {
            "id": "2",
            "content": "2번",
            "postType": "Answer",
            "usedEmoticons": []
          },
          "cursor": "2"
        },
        {
          "node": {
            "id": "1",
            "content": "1번",
            "postType": "Answer",
            "usedEmoticons": []
          },
          "cursor": "1"
        }
      ],
      "pageInfo": {
        "endCursor": "1",
        "hasNextPage": true
      }
    }
  }
}

장점

  • cursor기반으로 다음 페이지를 가져오기 때문에 데이터의 누락과 중복 문제가 없다.
  • 커서가 데이터를 정적으로 유지할 필요 없어 실시간 데이터를 효과적으로 처리 할 수 있다

단점

  • cursor가 중복없고 순차적이어야한다.
  • 사용자가 특정페이지로 옮기지 못한다

Reference

(typegraphql-relay)
https://github.com/calmonr/typegraphql-relay/blob/main/src/relay/node.resolver.ts
https://aerocode.net/326
https://bbbicb.tistory.com/40
https://americanopeople.tistory.com/355
https://graphql-kr.github.io/learn/pagination/
https://velog.io/@leejh3224/%ED%8E%98%EC%9D%B4%EC%A7%80%EB%84%A4%EC%9D%B4%EC%85%98-%EC%BB%A4%EC%84%9C%EA%B8%B0%EB%B0%98-%ED%8E%98%EC%9D%B4%EC%A7%80%EA%B8%B0%EB%B0%98

0개의 댓글