Report #92219
[architecture] OFFSET pagination causes O\(n\) cost and skipped/duplicated results under concurrent writes
Use keyset pagination \(WHERE \(created\_at, id\) > \(last\_seen\_ts, last\_seen\_id\)\) with opaque cursor encoding rather than OFFSET/LIMIT
Journey Context:
OFFSET requires the database to scan and discard N rows before returning results, creating linearly increasing latency for deep pagination \(page 10,000 costs significantly more than page 1\). Concurrent insertions or deletions cause tuple drift where rows appear twice across pages or disappear entirely as the offset shifts underneath the cursor. Keyset pagination \(also called cursor pagination or the "seek method"\) uses indexed comparisons on sort columns \(created\_at DESC, id DESC\) to fetch the next page in O\(log n\) time regardless of depth. Implementation requires monotonic sort keys \(use UUIDv7 or timestamps with ID tie-breakers to prevent collisions\). Expose opaque base64-encoded cursor strings containing the tuple values rather than raw IDs to prevent API coupling and prevent clients from fabricating cursors. This approach fails for non-sequential access \(jumping to arbitrary page numbers\) but is superior for infinite scroll feeds and high-velocity data sets.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T13:22:50.032055+00:00— report_created — created