GraphQL 페이지네이션
GitLab GraphQL API에서 사용하는 오프셋 페이지네이션과 키셋 페이지네이션의 원리, 구현 방법, 테스트 방법을 설명합니다.
페이지네이션 유형 # GitLab은 두 가지 페이지네이션 방식을 사용합니다. 오프셋 페이지네이션과 keyset 페이지네이션(커서 기반이라고도 합니다)입니다. GraphQL API는 주로 keyset 페이지네이션을 사용하며 필요할 때 오프셋 페이지네이션으로 폴백합니다. 성능 고려 사항 # 자세한 내용은 페이지네이션 일반 가이드라인 을 참고합니다. 오프셋 페이지네이션 # 가장 흔하게 쓰이는 전통적인 페이지 단위 페이지네이션이며 GitLab 전반에서 사용합니다. 페이지 하단의 페이지 번호 목록으로 알아볼 수 있으며, 번호를 선택하면 해당 페이지의 결과로 이동합니다. 예를 들어 Page 100 을 선택하면 백엔드로 100 이 전달됩니다. 한 페이지에 항목이 20개라면 백엔드는 20 * 100 = 2000 을 계산한 다음, 처음 2000개 레코드를 건너뛰어(오프셋) 데이터베이스를 조회하고 그다음 20개를 가져옵니다. page number * page size = where to find my records 이 방식에는 두 가지 문제가 있습니다. 성능. 100페이지(오프셋 2000)를 조회하면 데이터베이스는 해당 오프셋까지 테이블을 스캔한 다음 이어지는 20개 레코드를 가져와야 합니다. 오프셋이 커질수록 성능이 빠르게 저하됩니다. 자세한 내용은 The SQL I Love <3. Efficient pagination of a table with 100M records 에서 확인할 수 있습니다. 데이터 안정성. 100페이지(오프셋 2000)의 항목 20개를 가져오면 GitLab은 그 20개를 표시합니다. 이후 누군가 99페이지 이전에서 레코드를 삭제하거나 추가하면 오프셋 2000의 항목은 다른 집합이 됩니다. 목록이 계속 바뀌기 때문에 페이지를 넘기다가 항목을 건너뛰는 상황까지 생길 수 있습니다. 자세한 내용은 Pagination: You're (Probably) Doing It Wrong 에서 확인할 수 있습니다. Keyset 페이지네이션 # 특정 레코드가 주어졌을 때 그다음에 오는 레코드를 계산하는 방법을 알고 있다면, 데이터베이스에서 바로 그 레코드들을 조회할 수 있습니다. 예를 들어 생성일 기준으로 정렬된 이슈 목록이 있다고 가정합니다. 페이지의 첫 항목이 특정 날짜(예: 1월 1일)라는 것을 알고 있다면, 그 날짜 이후에 생성된 모든 레코드를 요청해 앞의 20개를 가져올 수 있습니다. 항상 그 날짜 이후의 레코드를 요청하므로 다수가 삭제되거나 추가되어도 문제가 없고 올바른 항목을 얻습니다. 다만 1월 1일에 생성된 이슈가 20페이지에 있는지 100페이지에 있는지는 쉽게 알 수 없습니다. keyset 페이지네이션의 장점과 절충점은 다음과 같습니다. 성능이 훨씬 좋습니다. 삭제나 삽입 때문에 목록에서 레코드가 누락되지 않으므로 최종 사용자에게 더 안정적인 데이터를 제공합니다. 무한 스크롤을 구현하는 최선의 방법입니다. 구현과 유지 보수가 더 어렵습니다. updated_at 과 sort_order 에는 쉽지만 복잡한 정렬 시나리오 에는 복