모든 글

페이징 카운트 쿼리가 데이터베이스를 느리게 하는 이유

정확한 전체 건수가 제한 조회보다 비싼 이유와 슬라이스, 캐시 메타데이터, 추정치 또는 요구사항 변경을 선택할 기준을 설명합니다.

출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다. gpt-5.6-sol 모델을 사용해 생성·편집했습니다.

정확한 전체 페이지 수를 구하는 비용은 한 페이지의 데이터를 읽는 비용보다 훨씬 클 수 있다. 제한 조회는 필요한 행을 찾으면 멈출 수 있지만 카운트 쿼리는 조건에 맞는 전체 집합을 계산해야 한다. 카운트를 최적화하기 전에 사용자에게 정확한 총건수와 마지막 페이지가 정말 필요한지 먼저 물어야 한다.

많은 페이징 추상화는 두 번째 쿼리를 눈에 띄지 않게 만든다. 애플리케이션은 페이지 하나를 요청하지만 프레임워크는 목록을 가져온 뒤 전체 원소 수를 구하는 쿼리를 추가로 실행한다. 편리한 API가 DB 작업까지 없애는 것은 아니다.

리밋은 결과만 제한하고 카운트는 제한하지 않는다

필터링한 목록에서 열 개를 보여준다고 하자. 적절한 접근 경로가 있다면 DB는 필요한 구간을 찾은 뒤 멈출 수 있다. 그러나 정확한 전체 건수와 마지막 페이지를 보여주려면 카운트에서 조건에 맞는 집합 전체를 평가해야 한다.

비용은 데이터 규모, 쿼리와 인덱스에 따라 달라진다. 작은 테이블에서는 아무 문제도 없을 수 있고 좋은 인덱스로 충분히 버틸 수도 있다. 그래도 싸다고 가정하지 말고 실제 쿼리를 확인해야 한다.

운영 서비스와 같은 DB를 쓰는 어드민 조회도 영향을 줄 수 있다. 넓은 검색 조건에 정확한 카운트를 반복하면 사용자 트래픽이 늘지 않았는데도 CPU와 메모리를 경쟁해서 쓸 수 있다.

장치를 추가하기 전에 제품의 약속을 바꿀 수 있는지 본다

정확한 전체 건수와 마지막 페이지가 필요 없다면 슬라이스나 목록으로 충분할 수 있다. 이는 리포지토리 반환 타입만의 문제가 아니라 제품 선택이다.

전체 건수가 필요하다면 별도 메타데이터나 캐시로 관리할 수 있다. 결과가 매우 많다면 근사치나 제한된 페이지 표시도 고려할 수 있다.

구글은 근사치나 변하는 총건수를 보여주고 표시한 모든 페이지가 존재하지 않을 수도 있는 검색 화면의 사례로 언급된다. 다만 내부 구현은 알 수 없다.

제품 요구사항이 먼저다. 사용자에게 정확한 총건수나 마지막 페이지로 바로 가는 기능이 필요 없다면 슬라이스나 목록으로 카운트를 피할 수 있다. 총건수가 필요하다면 쿼리를 유지하거나, 별도 메타데이터나 캐시를 쓰거나, 근사치 또는 제한된 범위만 보여줄 수 있다. 실제 쿼리 비용과 제품이 보여줘야 하는 정보에 따라 선택한다.