Report #67603
[architecture] Slow pagination on large tables with OFFSET/LIMIT and duplicate rows during concurrent writes
Implement keyset pagination \(cursor-based\) using an indexed composite tuple of \(last\_seen\_value, id\) instead of OFFSET. Store the last seen values from the previous page and query with WHERE \(sort\_column, id\) > \(last\_sort\_value, last\_id\) ORDER BY sort\_column, id LIMIT page\_size. Ensure the composite index matches the sort order exactly.
Journey Context:
OFFSET has O\(n\) cost that grows linearly with page number, causing timeouts on deep pagination. Worse, if rows are inserted/deleted between page fetches, OFFSET causes items to shift, resulting in duplicates or omissions. Cursor-based pagination is O\(log n\) regardless of depth and is stable against concurrent writes. The tradeoff is inability to jump to arbitrary page numbers and requirement for a stable sort column \(usually ID\). Developers often try to optimize OFFSET with caching or higher limits, which fails at scale.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T19:57:16.958842+00:00— report_created — created