Question presented to candidate: "Our article feed uses LIMIT 20 OFFSET n and the deep pages are getting slow; users also report seeing the same article twice when they click next. What is going on, and how would you paginate this efficiently?"
What a strong answer should cover:
- Why
OFFSET nis slow on deep pages: the database still produces and throws away the first n rows, so page cost grows with page depth even with an index - Why
OFFSETpages drift: rows inserted or deleted between requests shift every later page, so rows repeat or are skipped - Keyset (seek) pagination: remember the sort key of the last row seen and ask for rows after it,
WHERE (published_at, id) < (:last_date, :last_id) ORDER BY published_at DESC, id DESC LIMIT 20 - A unique tiebreaker in both the
ORDER BYand the cursor, and a composite index in exactly that order, so the next page is one index seek - Trade-offs: keyset cannot jump to page 517 and needs an opaque cursor in the API; total counts (
COUNT(*)) are a separate, full-cost query; row-value syntax differs by engine
Clarifying questions expected:
- Do users need to jump to an arbitrary page number, or only next / previous (infinite scroll)?
- What is the sort order, and is it unique? If not, what is the tiebreaker?
- Do we need an exact total count, or is "more results" enough?
Code / implementation expected: Yes β the OFFSET query, the keyset query with a tiebreaker, the index that supports it, and ideally a plan showing the difference.
Schema used by the examples: