똑같은 삽질은 2번 하지 말자

Pagination의 Offset-based과Cursor-based 본문

카테고리 없음

Pagination의 Offset-based과Cursor-based

곽빵 2022. 2. 7. 21:35

개요

Offset-based와 Cursor-based

nodejs에서 pagination으로 Offset-based pagination과 Cursor-based pagination 주로 사용되는 2개의 방법이 존재하는데

그에 관해 기록해두고자 한다.

 

Offset-based pagination

Offset은 SQL과 직접적으로 비교하면 조금더 이해하기 쉬운데,

SQL에 있어서 offset과 limit을 같이 사용할 때 의미는 몇번째(offset)데이터 부터 갯(limit)만큼 가져온다. 라는 의미다.

3번째와 4번째데이터를 취득할 시 offset:2 limit:2 가 된다.

(한 페이지당 불러오는 데이터의 수가 2개 일때 3페이지의 offset은 3 * 2가 되고 limit는 고정적으로 2이다.)

offset-based는 새로운 데이터가 추가될 때, 문제가 될 수 있는데

[0,1,2,3,4,5,6] 이라는 데이터가 존재한다. 이 때 2페이지에 있는 데이터를 호출하려고 하는데 0와 1사이에 새로운 데이터 7이 추가된다. 그러면 2페이지로써 취득하는 데이터는 [7,2]가 되버리는 의도치 않게 1페이지에 있던 데이터가 밀려 들어온 것이다.

반대로 삭제할 경우에는 누락되는 데이터가 존재할 수 도 있는것이다.

 

그리고 SQL에서 offset이 동작하는 방식을 보면 offset-based방식이 비효율적으로 보여지는데

왜냐하면 offset은 레코드를 조회하기 전에 데이터베이스가 offset만큼 레코드를 건너 뛰는 동작을 한다.

그럼 데이터의 양이 방대하면 방대할수록 페이지가 뒤로가면 뒤로갈수록 데이터를 가져오는데 시간이 더 걸릴 수 있다.

 

Cursor-based Pagination

오히려 더 간단할 수 있는데 Cursor-based는 limit는 그대로 보내는데, offset 대신에 lastId(cursor)를 보낸다.

SQL은 처리를 lastId 이후에 존재하는 데이터를 갯수(limit)만큼 반환하는 것이다.



cursor-based는 아까의 offset-based의 중복된 데이터나 건너뛰는 데이터를 방지할 수 있다.

그리고 방대한 양의 데이터를 페이징할 때도 offset을 사용하지 않으므로 시간복잡도가 O(N) -> O(1)로 된다.

 

하지만, 역시 단점도 존재하는데

cursor라는 친구는 절대 중복된 값이 존재하면 안되고, 고유의 순서를 가진 데이터이어야 한다.

그런 제한적인 조건이 제한된 정렬기능가 이어진다. 기준이 되는 데이터(cursor)가 아니면 정렬기준이 못되기 때문이다.

그리고 offset-based와 비교하면 구현하기 조금 까다롭다라고 한다.

 

상황에 따라 적합한 방식으로 페이징을 하자

이 두 pagination 방식은 각각 적합한 케이스가 다르다
Offset-based는 목록 속의 특정 범위의 집합을 빼내기에 아주 적합하다. (2페이지에서 바로 10페이지 보기)
구체적으로는 Google 검색 결과의 페이지를 보면 된다.

여기서 다이렉트로 3페이지로 옮기고 싶을 때 페이지당 표시건수가 20건이라면 offset:40, first:20으로 지정하면 된다.

Cursor-based에서는 이러한 전이에는 기본적으로 적합하지 않다. lastId(cursor)로 지정하게 될 데이터는 지난번 취득 결과에서 꺼내게 되므로 2페이지를 취득할 때까지는 lastId(cursor)로 지정하는 값을 모르기 때문이다.


Cursor-based가 적합한 것은 Twitter의 타임라인과 같은 전회의 취득 결과로부터 최신의 차분만을 취득하고 싶은 경우이다.

흔히들 알고있는 무한 스크롤!  항상 이전 결과로부터 취득한 값의 끝을 다음 질의 cursor로 지정하면 되므로 아주 적합하다.

이 두 가지에 있어서는 어느 쪽이 뛰어난 것은 아니고, 적합한 상황에서 적합한 페이지네이션을 사용하면 된다.

Comments