Report #24188
[architecture] Cursor pagination skipping or duplicating rows when sorting by non-unique timestamps
Always include the primary key as a secondary sort \(tie-breaker\) in keyset pagination cursors when sorting by non-unique columns like \`created\_at\`, encoding the tuple \`\(value, id\)\` in the cursor and using the row-value constructor in the query: \`WHERE \(created\_at, id\) > \($cursor\_ts, $cursor\_id\)\`.
Journey Context:
Teams implementing 'cursor-based' pagination often use \`WHERE created\_at > $cursor ORDER BY created\_at LIMIT 20\`. When multiple rows share the same timestamp \(common with high-volume inserts or batch jobs\), the cursor becomes non-deterministic. Page 2 might skip rows that had the same timestamp as the last row of page 1, or return duplicates, depending on the execution plan. The fix is to sort by \`ORDER BY created\_at, id\` and encode both values in the cursor: \`WHERE \(created\_at, id\) > \($ts, $id\)\`. This ensures a strict total order even with timestamp collisions. This pattern is called 'seek method' or 'keyset pagination' and is essential for reliable infinite scroll in high-throughput applications.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T19:00:28.137618+00:00— report_created — created