DB

게시글 페이지 번호로 조회

gucoding 2025. 5. 28. 02:22

게시글을 조회할 때 페이지 번호로 조회한다는 요구사항이 있다면 일반적으로 생각하기에는 게시글의 총 개수가 필요하다고 생각이 듭니다.
가령, 한 페이지 당 10개의 게시글을 보여주고 페이지번호를 1~10까지 보여준다고 가정합시다.

총 게시물이 40개가 있다면 (1~4)페이지버튼, 이전버튼을 노출하면 되고,
총 게시물이 200개가 있다면 (1~10)페이지버튼, 이전, 다음버튼을 노출하면 됩니다. 그러나 모든 게시글의 개수를 매번 주는것은 얼마안가 성능에 영향을 끼칩니다.

select count(*) from post where board_id = 1;

+----------+
| count(*) |
+----------+
| 12020000 |
+----------+
1 row in set (1.09 sec)

Extra
Using index

커버링 인덱스로 동작하나 결국은 게시판의 모든 게시글을 세어야하니 느려질 수 밖에 없습니다...
과연 요구사항을 맞추려면 전체 게시글의 개수가 꼭 필요할까요?
예시를 들어봅시다.

사용자가 1~10번 페이지에 있으면 101개 까지의 게시글 개수만 알면 됩니다.
10번 페이지 이하에서는 이전버튼은 존재하지 않고, 101개 이상일 때, 다음버튼을 보여주면 됩니다.

사용자가 11~20번 페이지에 있으면 201개 까지의 게시글 개수만 알면 됩니다. 201개 미만이면 다음 버튼이 보이지않고, 201개 이상이면 보여줍니다. 그리고 10번 페이지 초과인 경우에는 이전버튼은 항상 존재하게 됩니다.

정리하면, 사용자가 현재 접속하고 있는 페이지 기준에 따른 게시글 개수로 판단하면 됩니다. 그리고 이걸 판단하는 로직을 코드로 보겠습니다.

public Long calculatePageLimit(Long page, Long pageSize, Long movablePageCount) {
        return ( ((page - 1) / movablePageCount) + 1 ) * pageSize * movablePageCount + 1;
    }
  • page: 현재 사용자가 보고 있는 페이지 번호 (예: 1, 2, 3...)
  • pageSize: 한 페이지당 보여줄 게시글 수 (예: 10)
  • movablePageCount: 한 번에 보여줄 페이지 버튼 그룹의 개수 (예: 10). 예를 들어, movablePageCount가 10이면, 110, 1120, 21~30 등의 페이지 그룹을 의미합니다.

이 메서드는 현재 페이지를 기준으로 사용자가 '다음' 버튼을 여러 번 눌러서 이동할 수 있는 최대 페이지 그룹의 끝까지의 게시글 개수를 예상하여 LIMIT 값을 계산합니다.

예를 들어, page = 1, pageSize = 10, movablePageCount = 10이라고 가정해봅시다.

calculatePageLimit(1, 10, 10) 계산:

  1. (page - 1) / movablePageCount: (1 - 1) / 10 = 0
  2. 0 + 1 = 1
  3. 1 * pageSize * movablePageCount: 1 * 10 * 10 = 100
  4. 100 + 1 = 101

즉, 첫 페이지(1페이지)에서 count를 조회할 때 LIMIT 101을 사용합니다.

select count(*) 
from (
      select post_id 
      from article 
      where board_id = :boardId limit :limit 
    ) 

서브쿼리에서 커버링 인덱스로 위에서 구한 limit 만큼 조회해서 개수를 따로 구합니다.

select *
from (
      select post_id 
      from post 
      where board_id = :boardId
      order by post_id desc 
      limit :limit offset :offset 
      t left join post on t.post_id = post.post_id
      )

제한적인 개수로 조회해서 성능을 올려보았습니다.

'DB' 카테고리의 다른 글

Secondary Index 예제  (0) 2025.05.26
[오늘의 문제] Secondary Index (보조 인덱스)  (0) 2025.05.26