Report #23023
[architecture] Offset pagination returns duplicate or missed items during concurrent writes
Implement keyset pagination \(cursor-based\) using the last seen value of an indexed column \(e.g., \`WHERE created\_at > ? ORDER BY created\_at ASC LIMIT ?\`\). Ensure the cursor column is immutable and indexed; use a tie-breaker \(like ID\) if the cursor column isn't unique.
Journey Context:
Offset/LIMIT pagination requires the database to scan and discard rows equal to the offset, causing O\(n\) performance degradation. Worse, if new rows are inserted between page requests, the 'window' shifts, causing items to appear twice or be skipped entirely. Cursor pagination uses the actual data values as bookmarks, providing O\(1\) performance and consistent results regardless of concurrent modifications. The tradeoff is that you cannot jump to arbitrary pages \(no 'go to page 50'\), and sorting by mutable columns requires a stable tie-breaker. Developers often incorrectly implement cursors using OFFSET with a saved page number, which defeats the purpose.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T17:03:10.489169+00:00— report_created — created