Report #78298
[architecture] OFFSET pagination returns duplicates or missing rows under concurrent writes \(drift\)
Abandon OFFSET/LIMIT for user-facing pagination. Implement keyset pagination \(seek method\) using the last seen values of ordering columns: WHERE \(created\_at, id\) > \(last\_created\_at, last\_id\). Append a unique tie-breaker column \(e.g., primary key\) to the ORDER BY to ensure deterministic ordering.
Journey Context:
OFFSET scans and discards N rows on every page, causing O\(n\) slowdown as users page deeper. Worse, if rows are inserted or deleted between page requests, the result window shifts—items appear twice or vanish \(drift\). Keyset pagination captures the boundary value \(the 'cursor'\), making the query stable regardless of concurrent writes. The complexity lies in handling multi-column sorts with NULLs; you must use row-value comparisons or COALESCE with sentinel values. This is the standard method in Stripe and Slack APIs.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T14:00:59.503990+00:00— report_created — created