Report #70877
[architecture] Slow pagination queries on large tables using LIMIT OFFSET
Implement keyset pagination \(cursor-based\) using the last seen value of an indexed column: \`SELECT \* FROM orders WHERE \(created\_at, id\) > \(?, ?\) ORDER BY created\_at, id LIMIT 20\` instead of \`OFFSET\`. Store the composite cursor \(timestamp \+ id\) to handle tie-breaking deterministically.
Journey Context:
OFFSET pagination has O\(n\) cost - the database must scan and discard all offset rows. At page 10,000, this causes timeouts. Common mistake: 'Just add an index' - indexes don't fix the offset scan cost. Alternatives: 1\) Seek method \(keyset pagination\) - O\(log n\) via index seek, 2\) Search-after \(cursor-based\) - maintains state. Tradeoffs: Cursor pagination cannot jump to arbitrary page numbers \(loses 'go to page 50'\), requires deterministic sort order \(must include unique column like ID in sort key to handle ties\), and cursor state must be maintained client-side. For APIs returning data to end-users with numbered pages, use cursor-based 'next/previous' links rather than page numbers. Only use OFFSET for small datasets \(<10k rows\) or admin tooling.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T01:32:30.760919+00:00— report_created — created