나만보는개발공부블로그

[Pagination] Offset-based vs Cursor-based 본문

Web Development

[Pagination] Offset-based vs Cursor-based

alexrider94 2022. 4. 16. 21:07

많은 데이터를 한번에 가져오면서 API서버에 한번에 많은 요청을 하게 되어 API요청시에 에러가 발생해서 페이지를 통해 데이터를 불러와야하는 상황이 생겼고 페이지 방식으로 데이터를 불러오는 방법을 찾아보고 성능적으로 어떻게 불러와야 좋은지 찾아보다가 Offset과 cursor 관련 페이지네이션에 대해서 검색을 통해 알게되었고 그 내용을 정리하고자 글을 작성합니다.

1. Offset-based Pagination


- 페이지네이션을 서버단에서 쿼리를 통해 작성하게 되는데 페이지 단위로 데이터를 불러올시에 LIMIT을 사용해서 데이터를 가져옵니다.

SELECT something FROM table ORDER BY created desc LIMIT 20,40
OR
SELECT something FROM table ORDER BY created desc LIMIT 20 OFFSET 20

 - 보통은 게시판 페이지마다 데이터를 가져올 경우 흔히 사용하게됩니다.
 
 * 문제점

1. 데이터변화가 있을시에 중복으로 데이터가 노출될 가능성

- 어떠한 페이지를 보고있었는데 새로운 데이터가 등록되었고 그 후에 다음 페이지로 이동시에 같은 데이터를 볼 가능성이 생깁니다.
2. 성능 이슈
- offset 기반으로 쿼리를 실행시에 임시로 해당 쿼리의 모든값을 만들고 정해진 갯수로 자르는 방식으로 데이터를 처리합니다.  만약 데이터가 많아질경우 문제가 생기는데 쿼리가 "LIMIT 50000, 20"이라는 절을 사용하는 경우 실제로 데이터베이스에 50,020개의 행을 살펴보고 처음 50,000개를 버리도록 요청하는게 되어서 결국은 성능저하를 일으킬수 있습니다.

 

쿼리 저하 그래프

 

2. Cursor-based [Seek] Pagination 

- 커서기반의 페이지방식은 어떠한 유니크 값을 가지고 페이지를 처리하면 됩니다. 어떠한 한 값을 가지고 그 값을 비교해서 데이터를 자르는것입니다. 여기서 오프셋과 다른점은 어떠한 값뒤에 있는값을 바로 가져오는 방식이라 오프셋에서의 n개의 skip한 row의 다음 10개 받는게 아니라 한 row의 다음 10개를 받는것이라 할 수 있다.

보통은 id값을 이용해서 처리할 수 있습니다.

SELECT something FROM table WHERE id < cursor ORDER BY id desc LIMIT 20

쿼리는 작성하기 쉬워보이지만 어떠한 조건들이 걸리게 될 경우 조금 어렵게 됩니다.
최근 생성된 데이터를 가져와야하는 조건이 생긴다면 OR 문을 사용해서 처리해야합니다.

커서 기반의 페이지네이션은 보통 무한스크롤링에 사용되고 유저가 실시간으로 사용하는 데이터들을 다루거나 데이터가 많을 경우 사용하면 좋을 것 같습니다.




참고 사이트

- https://www.eversql.com/faster-pagination-in-mysql-why-order-by-with-limit-and-offset-is-slow/