Keyset Pagination vs Offset
Efficient keyset (cursor) pagination pattern compared to traditional OFFSET for large datasets in PostgreSQL.
-- Traditional OFFSET pagination (slow for large offsets)
SELECT id, title, created_at
FROM posts
ORDER BY created_at DESC, id DESC
LIMIT 20 OFFSET 1000;
-- Keyset pagination (fast at any depth)
-- First page
SELECT id, title, created_at
FROM posts
ORDER BY created_at DESC, id DESC
LIMIT 20;
-- Next page: use the last row's values as cursor
SELECT id, title, created_at
FROM posts
WHERE (created_at, id) < ('2024-01-15 10:30:00', 42)
ORDER BY created_at DESC, id DESC
LIMIT 20;
-- Create index to support keyset pagination
CREATE INDEX idx_posts_cursor ON posts (created_at DESC, id DESC);
-- Helper: get total count efficiently
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE relname = 'posts';Use Cases
- API list endpoints
- Infinite scroll backends
- Large dataset browsing
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Materialized View with Auto-Refresh
Create and maintain materialized views for expensive aggregate queries with concurrent refresh support.
LATERAL Join for Top-N Per Group
Use LATERAL joins to efficiently fetch the top N related rows per group without window function subqueries.
UPSERT with ON CONFLICT
Insert or update rows atomically using PostgreSQL ON CONFLICT clause with partial indexes and conditions.
Full-Text Search with Ranking
PostgreSQL full-text search using tsvector, tsquery, and ts_rank with trigram similarity for fuzzy matching.