Report #35097
[architecture] OFFSET-based pagination is slow and inconsistent for large datasets with frequent inserts
Implement keyset pagination \(cursor/seek method\) using the last seen value of an indexed column \(e.g., created\_at, id\) in the WHERE clause instead of OFFSET
Journey Context:
OFFSET 100000 LIMIT 20 forces the database to scan, sort, and count through 100,020 rows then discard the first 100,000—latency grows linearly with page depth. It also suffers from drift: if new rows are inserted between requests, items shift, causing duplicates or omissions across pages. Keyset pagination \(seek method\) remembers the last value from the previous page \(e.g., last\_created\_at\) and queries WHERE created\_at > $last\_val ORDER BY created\_at LIMIT 20. This uses the index to jump directly to the starting point \(O\(log n\)\) and is stable against new insertions \(they simply won't appear in the current iteration\). Requirements: a unique, sortable column or composite tuple \(created\_at, id\) to handle ties; cannot jump to arbitrary page numbers \(no 'page 500' link\) without previous cursors; sorting by multiple directions complicates the WHERE clause \(need row value constructors\). Never use OFFSET for deep pagination in production APIs.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T13:22:52.395710+00:00— report_created — created