대량의 글들을 보여주는 SNS 피드와 공지사항 게시판의 글들은 어떤 방식으로 응답받아 보이는 것일까? 다른 요청들과 마찬가지로 한 번의 요청에서 필요한 모든 데이터를 전달받을까? 공지사항과 같은 게시판은 주로 데이터를 페이지별로 나눠 보여주며, SNS 피드는 화면 맨 아래에 도달했을 때 데이터를 추가로 로드해 보여주고 있음을 확인할 수 있다. 이처럼 많은 양의 데이터를 다룰 때 전체 데이터를 한 번에 보여주는 것이 아니라, 필요한 양 만큼의 단위로 데이터를 나눠 받아 보여주는 방식을 페이지네이션이라고 한다.
이는 전자의 방식보다 네트워크 부하를 줄이고 보다 효율적인 통신을 가능하게 한다. 페이징이라고도 불리는 이 기법을 구현하는 방법으로는 크게 두 가지가 있으며, 오프셋 방식과 커서 방식이 그 방법이다. 두 방식 모두 데이터를 정렬한 뒤 한 번에 보낼 양만큼의 데이터 세트를 만들어 한 응답에 하나의 세트를 전달하며, 둘의 차이는 세트 구성 방법에 있다.
오프셋 기반 방식(offset-based pagination)
오프셋 기반 방식(offset-based pagination)은 MySQL 기준 limit과 offset을 활용하는 방식으로, 세트의 첫 번째 시작 데이터를, 한 번에 다루는 데이터의 개수를 기준으로 계산한 위치(offset)에서부터 일정량(limit)의 데이터를 반환한다. 이는 직관적이고 이해하기 쉬우며 구현도 커서 기반 방식에 비해 비교적 더 간단하다는 장점을 갖는다.
하지만 문제는 데이터 제공 후 그다음 세트를 보내는 사이에 새로운 데이터가 추가되거나 삭제되었을 때 발생한다. 간단한 예시로 최신순으로 정렬한 글 데이터를 반환하는 작업 중 이미 하나의 세트를 보낸 상태에서 그다음 세트를 계산해 보내는 사이에 새로운 글이 추가되었다고 가정하면 정렬 순서가 하나씩 밀려 이미 제공한 데이터가 새로 구성하는 세트에 한 번 더 추가되어 중복으로 데이터를 제공하는 문제가 발생하는 것이다. 비슷한 방식으로 데이터 삭제의 경우에는 데이터 누락 문제가 생기게 된다.
또 다른 문제점은, 세트 구성 과정에서 full table scan을 통해 offset만큼의 데이터를 훑고 offset 이전의 데이터는 세트에 포함되지 않는 방식으로 진행돼 데이터의 양이 많아질수록 해당 방식은 비효율적이고 DB에는 큰 부하가 가하는 작업이 된다. 이러한 문제점들을 바탕으로, 오프셋 기반 방식은 데이터의 삽입, 삭제가 빈번하지 않고 총 데이터의 양이 많지 않을 때만 도입하는 것이 좋다는 결론을 내게 된다.
커서 기반(키셋 기반, cursor-based pagination, keyset-based pagination)
커서 기반(키셋 기반, cursor-based pagination, keyset-based pagination) 방식은 MySQL에서 offset은 사용하지 않고 limit과 where 절을 사용하여 위 두 문제를 해결한다. 세트 구성의 시작 데이터를, 제공한 데이터의 개수를 기반으로 계산해 구하는 것이 아닌, 클라이언트 측에 저장해 둔 커서 키값을 where 절에서 바로 사용해 비효율적인 Full Table Scan을 수행하지 않는다.
이때 커서는 마지막으로 전달된 데이터를 가리키는 것으로, 세트의 시작 데이터를 마지막으로 보낸 데이터의 다음 데이터로 정하는 것이다. 이를 통해 오프셋 기반 방식의 문제점이었던 데이터의 중복 혹은 누락 문제 역시 해결된다. 커서, 키값은 응답을 받았던 클라이언트 측에서 저장하고 있으며 그다음 세트를 받기 위해 해당 값을 서버로 전달돼 사용되며 이는 데이터 식별을 위해 중복없이 유일해야 하므로 기본 키 혹은 생성 일자 및 시간 정보가 그 역할을 한다.
이렇듯 커서 기반 방식은 오프셋 기반의 방식의 단점을 해결하는 대안이지만 페이지 간의 불연속적인 이동은 불가하다는 한계를 갖는다. 또한 데이터에 기본 정렬 조건이 추가되는 경우 쿼리가 복잡해진다는 단점도 지닌다.
각 방식의 특징을 고려하여, SNS와 같이 실시간 데이터 처리 등으로 데이터의 변경이 빈번한 경우엔 커서 기반 방식을, 공지사항 게시판과 같이 그렇지 않을 때는 오프셋 기반 방식을 택하여 개발하는 것이 좋을 것으로 보인다는 결론을 내릴 수 있다. 개발하고자 하는 서비스의 특성에 따라 적절한 페이지네이션 기법을 선택해 개발해야겠다.
정리
오프셋 기반 방식
- 불연속적인 페이지 간 이동이 가능하다.
- 직관적이고 이해하기가 쉽다.
- 구현이 간단하다.
- 데이터 중복 반환, 누락 문제가 발생할 수 있다.
- full table scan으로 대량의 데이터를 다룰 시 비효율적이다.
- 데이터가 빈번하게 생성, 삭제되는 서비스에 맞지 않다.
- 공지사항 게시판과 같은 서비스에 적합하다.
커서 기반 방식
- 데이터 중복 반환, 누락 문제가 발생하지 않는다.
- full table scan을 하지 않아 속도가 더 빠르다.
- 불연속적인 페이지 간 이동이 불가능하다.
- SNS 서비스의 무한 스크롤 기능에 적합하다.