HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🛁
공부기록
/
🍀
Spring
/
🪢
Paging 처리해보자 !
🪢

Paging 처리해보자 !

태그
페이지네이션(페이징)Offset-based Pagination (오프셋기반)실제 쿼리(mysql기반)offset 기반의 고려해볼 사항Cursor-based Pagenation (커서 기반)cursor 기반의 고려해볼 사항Offset vs CursorREF
 

페이지네이션(페이징)

  • 서버와 클라이언트의 상황에서 보통 모든 데이터를 한번에 가져오지 않습니다.
  • 보통은 필요한 갯수를 저장하고 상황에 맞춰 정렬기준이 조건에 추가됩니다.
    • 정렬기준+갯수
  • 이러한 조건을 맞춰서 데이터를 가져오는 것을 Pagenation, 페이징이라고 합니다.
  • 페이지네이션을 처리하는 방법으로는 대표적으로 오프셋방식, 커서방식이 존재합니다.
 

Offset-based Pagination (오프셋기반)

실제 쿼리(mysql기반)

SELECT user_id FROM member ORDER BY created_at DESC LIMIT 20,40
  • 좀 더 일반적인 변수를 사용한 쿼리문
    • pagenum → 페이지(1,2..)
    • takenum → 한번에 불러올 데이터(row) 수
SELECT user_id FROM member ORDER BY created_at DESC LIMIT + ($takenum*($pagenum-1)) + ',' + $takenum
  • 매우 직관적이고 이해하기가 쉬우며 사용하기도 편리합니다. 보통 밑에 이동할 수 있는 페이지가 있고 페이지를 건너 뛸 수 있다면 offset 기반입니다.
 

offset 기반의 고려해볼 사항

  • 사용자가 매우 많은 사이트에서 글을 쓰는 사람이 매우 많다면? 초당 평균 20개의 새로운 데이터가 들어온다 가정하고 한 페이지당 20개의 데이터를 보여준다면 ?
  • 이를 오프셋 기반으로 구현을 한다면 1페이지의 20개의 글을 본 사람이 2페이지의 글을 보려고 눌렀을 때 방금 본 20개의 데이터를 그대로 보게되는 현상이 발생하게 됩니다.
  • 즉 중복데이터를 출력하게 되며 이런 최악은 아니더라도 이런 상황은 빈번하게 나타나게 될 것입니다.
  • 또한 정렬기준 조건에 따라서 row가 몇번 째 데이터인지 바뀌게 되는데, 당연히 DB는 모든 경우에 따른 rownum을 가지고 있지 않기 때문에 row의 개수가 많아질 수록 성능에 문제가 생기게 됩니다.
 

Cursor-based Pagenation (커서 기반)

  • cursor를 포인터라고 생각하면 이해가 더 쉬울 것이라 생각합니다.
  • curosr를 만들어 두고 포인터가 가리키는 것 다음부터 n개의 데이터를 주세요 하는 방법입니다.
  • 오프셋 방식같은 경우는 “n개의 데이터를 page-1만큼 스킵하고 그 다음 n개의 데이터를 주세요" 이런 흐름으로 요청이 이루어집니다.
  • 만약 cursor가 Integer로 된 id값이라면 id자체를 커서로 사용해도 상관은 없다.
    • 하지만 포인터를 회원가입 시기로 지정한다면 어떻게 될까? 만들어진 순서대로 출력하고 싶을 경우
 

cursor 기반의 고려해볼 사항

  • 상황 설명을 위해 LIMIT을 사용해서 현재 가정한 테이블의 상태는 아래라고 가정해 보겠습니다.
SELECT user_id, created_at FROM member ORDER BY created_at ASC LIMIT 4
 
user_id
created_at
123
1
124
2
120
3
114
4
  • 별다른 문제가 없어 보이지만 만약에 user_id가 “114”와 동시에 가입한 “115,116,117”이 있을 경우에?
  • cursor를 created_at으로 설정할 경우 cursor>4인 리스트를 다음 페이지에 불러올 텐데 그럴 경우에 115,116,117의 데이터는 누락이 발생하게 됩니다.
🔥
커서 기반 페이지네이션을 위해서는 정렬 기준에 포함되는 필드 중 하나이상은 반드시 고유값을 가져야 한다!
  • 다른 예시로 테이블을 한번 수정한 결과는 아래와 같습니다.(억지스럽지만 age는 중복값이 없다고 가정합니다.)
SELECT user_id, created_at FROM member WHERE (created_at > 4) or (created_at=4 and age> 20) ORDER BY created_at ASC LIMIT 4
user_id
created_at
age
123
1
17
124
2
18
120
3
19
114
4
20
  • 이렇게 쿼리를 날린다면 creaetdAt이 4인 115,116,117의 데이터는 누락되지 않습니다. 이제 문제가 모두 해결된 것처럼 보이지만 여기서도 문제점을 한번 더 생각해볼 수 있습니다.
  • 이렇게 조건절에 필요사항이 달림에 따라서 클라이언트 측에서도 이를 이해하고 ORDER BY에 달려있는 필드들을 이해하고 이에 해당하는 값들을 요청시 마다 보내야 하는데
  • 당연히 클라이언트 측은 이런걸 좋아하지 않고 원치 않습니다. 그렇기 때문에 WHERE절에 걸리는 조건들을 이용해서 고유한 값인 커서를 만들면 됩니다.
    • 간단한 예시로 createdAt이 최대 6자고 age가 최대 3자라고 가정하면
    • 두 가지를 합쳐서 4+17 ⇒ 000004017 이런식으로 가공해서 커서 값으로 사용을 하는 것이다. 커서를 기준으로 출력 후 그 다음 리스트는 이 커서 기준으로 다음 데이터를 가지고 오면 위의 문제점들이 해결이 됩니다.
 

Offset vs Cursor

  • 위의 두개 기준으로만 보면 커서 방식이 더 좋아 보이지만 데이터의 입력이 매우 드물고 또는 중복되는 데이터가 나와도 크게 상관이 없는 경우, 데이터의 수 자체가 많지 않아서 성능 고려를 딱히 안해도 되는 경우에는 오프셋을 사용하는 것도 하나의 방법이 될 것 같습니다.
  • 하지만 유저가 접속해서 사용하는 경우 커서기반 페이징 방식을 사용하는것이 좋습니다.
 

REF

Pagenation(페이징) [Offset-based, Cursor-based)
보통 필요한 갯수를 지정하고 상황에 맞춰 정렬기준이 조건에 추가됩니다( 정렬기준 + 갯수) - 이러한 조건을 맞춰서 데이터를 가져오는 것을 Pagenation(페이지네이션), 페이징 이라고 합니다. - 페이지네이션을 처리하는 방법으로는 대표적으로 1. 오프셋 기반 페이지네이션, 2.커서 기반 페이지네이션 - 비교적 구현이 매우 간단한 오프셋 기반 페이지네이션 부터 살펴보겠습니다. - 제가 사용하는 MySQL로 말씀드리자면 LIMIT을 사용하여 개수를 지정하면 됩니다.
Pagenation(페이징) [Offset-based, Cursor-based)
https://daeuungcode.tistory.com/128
Pagenation(페이징) [Offset-based, Cursor-based)
왜 오프셋 페이징보다 커서 페이징일까?
※ 이 글은 위 글을 의역한 글입니다. 커서 기반 페이징이 가장 효율적인 방법이며, 가능한 항상 사용되어야 한다 -페이스북 개발자 페이징은 책 페이지처럼 데이터를 묶음으로 분리하는 과정이다. 페이징은 크게 2개로 나뉘는데, 둘 중 뭐가 좋을까? 한 번 알아보자. 이 방법은 수십년동안 효과적으로 사용된 방법이다. OFFSET 값을 포함한 SQL 쿼리문을 동반한다.
왜 오프셋 페이징보다 커서 페이징일까?
https://bbbicb.tistory.com/40
왜 오프셋 페이징보다 커서 페이징일까?
커서 기반 페이지네이션 (Cursor-based Pagination) 구현하기
사실 처음에는 이 주제로 포스트를 쓰려고 했던건 아니고 Apollo GraphQL 에서 커서 기반 페이지네이션 구현 을 주제로 글을 쓰려고 했습니다. 그런데 막상 찾아보니 백엔드-프론트엔드를 함께 고려하여 커서 기반 페이지네이션을 잘 설명해 놓은 포스트가 없는 것 같아 이 글을 먼저 쓰게 되었습니다. 페이지네이션? 보통 서버에서 데이터를 가져올 때 모...
커서 기반 페이지네이션 (Cursor-based Pagination) 구현하기
https://velog.io/@minsangk/%EC%BB%A4%EC%84%9C-%EA%B8%B0%EB%B0%98-%ED%8E%98%EC%9D%B4%EC%A7%80%EB%84%A4%EC%9D%B4%EC%85%98-Cursor-based-Pagination-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0
커서 기반 페이지네이션 (Cursor-based Pagination) 구현하기
How to Implement Cursor Pagination Like a Pro
So you've decided to implement cursor pagination on your website. Well, you've come to the right place! (If you're not entirely convinced cursors is right for you, first, check out the benefits in this article to see if it is, indeed, the right option for you.)
https://medium.com/swlh/how-to-implement-cursor-pagination-like-a-pro-513140b65f32
How to Implement Cursor Pagination Like a Pro