Report #40618
[architecture] OFFSET-based pagination performance degradation on large datasets
Implement keyset pagination \(cursor-based\): encode the last seen values of the sort columns \(e.g., created\_at, id\) into an opaque cursor. Query using WHERE \(created\_at < $cursor\_date\) OR \(created\_at = $cursor\_date AND id < $cursor\_id\) with appropriate composite index. Never use OFFSET for large tables.
Journey Context:
OFFSET requires the database to scan and discard N rows before returning results, resulting in O\(offset\) time complexity. With millions of rows, page 1000 becomes orders of magnitude slower than page 1. Cursor pagination uses the index to jump directly to the starting position \(O\(log n\)\). Tradeoffs: you cannot jump to arbitrary page numbers \(no 'go to page 50'\), and sorting must be deterministic \(requires unique tie-breaker like ID\). Common mistake: using UUID as cursor without including the sort column in the index, or forgetting to handle the 'equal' case in the WHERE clause for composite sorts, causing missed rows.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T22:39:02.700484+00:00— report_created — created