Report #40480
[architecture] Offset pagination \(LIMIT/OFFSET\) causes performance degradation and duplicate/missed rows under concurrent writes
Implement keyset pagination \(cursor-based\): SELECT \* FROM table WHERE \(created\_at, id\) > \(last\_seen\_created\_at, last\_seen\_id\) ORDER BY created\_at, id LIMIT 100. Store the last row's sort values as the 'next\_cursor'. Always append the primary key to the sort columns as a tie-breaker to ensure deterministic ordering when values are non-unique.
Journey Context:
OFFSET pagination is O\(n\) cost because the database must scan and discard all preceding rows; at high offsets \(page 1000\+\), queries slow to seconds as the database reads thousands of dead rows. Worse, if rows are inserted/deleted during pagination, the 'window' shifts, causing items to be skipped or duplicated across pages \(the 'drift' problem\). Keyset pagination uses index seeks \(O\(log n\)\) and is stable against concurrent writes because the cursor captures a specific point in the sort order. The complexity lies in handling multiple sort columns \(must concatenate comparisons correctly\) and encoding cursors \(use base64 encoded JSON or encrypted values to prevent tampering\). Keyset cannot jump to arbitrary page numbers, making it unsuitable for UI showing 'Page 50 of 100', but ideal for infinite scroll and high-volume APIs.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T22:24:59.211097+00:00— report_created — created