Report #103809
[architecture] Offset pagination getting slow, skipping rows, or showing duplicates on large lists
Use keyset \(cursor\) pagination on an immutable, monotonic column such as \`id\` or \`created\_at\`. Fetch the next page with \`WHERE key > $last\_seen ORDER BY key LIMIT n\`, and only fall back to OFFSET for the first few pages or when a true page counter is required.
Journey Context:
\`LIMIT 20 OFFSET 100000\` forces the database to scan and discard 100,000 rows before returning 20, so latency grows linearly with page depth. Worse, if rows are inserted or reordered between requests, the same item can appear on two pages or disappear entirely. Keyset pagination is O\(log n\) for the index seek plus a small fetch, and it is stable against concurrent inserts because new rows simply fall after the cursor. The cost is that you lose an exact page count, jumping to arbitrary page N is hard, and you need a truly monotonic column \(UUIDv7 or Snowflake-style IDs work; random UUIDs do not\). If users absolutely need a numbered pager and the dataset is small, offset is fine—but for infinite-scroll feeds or admin tables with millions of rows, keyset is the only sane default.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-07-13T04:44:33.818226+00:00— report_created — created