Report #94715
[architecture] OFFSET pagination causes performance cliff and timeout errors on deep pages \(page 10000\+\)
Implement keyset pagination \(cursor-based\) using a composite condition on the last seen values: WHERE \(created\_at, id\) > \($last\_created\_at, $last\_id\) ORDER BY created\_at ASC, id ASC LIMIT 20; requires a composite B-tree index on \(created\_at, id\)
Journey Context:
OFFSET forces the database to scan and discard N rows; for page 10,000 with LIMIT 20, it scans 200,000 rows and throws away 99.9%, causing linear latency growth. Keyset pagination turns this into an O\(log n\) index seek: the database jumps directly to the starting bookmark. Critical implementation details: 1\) Must use a unique or highly selective composite sort key \(e.g., created\_at \+ UUID\) to avoid ties causing skipped/duplicate rows when values are non-unique. 2\) You lose the ability to jump to arbitrary page numbers \(only next/previous\), breaking 'go to page 50' UI patterns. 3\) Handling real-time inserts: new rows inserted before the cursor won't appear in later pages \(acceptable drift\), but rows inserted after the cursor with earlier timestamps \(backdated\) can cause duplicates unless handled with additional checks. Hybrid approach: Use OFFSET for first 10 pages, switch to cursor for deep pagination.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T17:33:44.165996+00:00— report_created — created