Reducing Count Query Cost in Pagination
What I Didn’t Know
While implementing pagination for the Gift API at Kakao Tech Campus, I used Spring Data JPA’s Page as the return type. During code review, my mentor pointed out:
“Page internally needs the total data count, so an extra count query runs.”
I had no idea that using Page triggers SELECT COUNT(*) on every request.
Why Is Count Query Dangerous?
With small datasets, it’s no big deal. But with millions of rows, COUNT(*) can become a serious bottleneck.
For infinite scroll UIs, you don’t even need the total count. But if you’re using Page, you’re paying for unnecessary count queries.
Mentor feedback:
“Page exposes a lot of unnecessary info internally—totalPages, totalElements, sort, numberOfElements… If the client doesn’t need all of this, you’re wasting serialization cost.”
“Try using Slice instead. Slice only checks if there’s a next page, so it skips the count query entirely.”
Page vs Slice
| Property | Page | Slice |
|---|---|---|
| Count query | Runs | Doesn’t run |
| Total page count | Known | Unknown |
| Has next page | Known | Known |
| Best for | Page number UI | Infinite scroll, “Load more” |
When to Use What?
Page
- When you need page numbers like “1 2 3 4 5 … 100”
- When you need to display total count like “2,340 products”
Slice
- Infinite scroll
- “Load more” button
- When total count is irrelevant
Lessons Learned
- Now I know that
Pagetriggers count queries - Use
Slicewhen total count isn’t needed - Always understand what the framework does under the hood
From Kakao Tech Campus 3rd cohort Gift API clone coding, summarizing mentor feedback.