Pagination performance
Skill Amey-Thakur/AI-SKILLS/skills/performance/pagination-performance
Plug-and-play skills and prompts for every AI coding agent
npx -y skills add Amey-Thakur/AI-SKILLS --skill pagination-performanceAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 21 days oldThe repository was created 21 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Paginate large result sets so page cost stays constant by using keyset (cursor) pagination instead of OFFSET, with a stable, encoded cursor. Use when deep pages get slow, an infinite scroll drifts or duplicates rows, or OFFSET grows with page depth.
SKILL.md
2.9 KB, 640 tokens by cl100k_base, as published. Nobody here has run it
Pagination performance
OFFSET 100000 LIMIT 20 makes the database read and discard 100,020 rows to
return 20: the deeper the page, the slower it gets, and concurrent inserts shift
rows under the reader. Keyset pagination fixes both by seeking to a remembered
position instead of counting from the start. Page cost stops depending on how
far in you are.
Method
- Diagnose the OFFSET cost.
EXPLAIN ANALYZEa deep page and watch rows scanned climb with the offset while the limit stays fixed. That linear growth, plus duplicate or skipped rows under concurrent writes, is the signal to abandon offset. - Paginate by keyset on a stable ordered column. Order by a unique,
monotonic key and carry the last row's value forward:
WHERE (created_at, id) < (:last_ts, :last_id) ORDER BY created_at DESC, id DESC LIMIT 20. The index seeks straight to the boundary, so page 10,000 costs what page 1 did. - Break ties with a unique tiebreaker. Order on a non-unique column alone (a timestamp) and rows sharing a value straddle the boundary, dropping or repeating on the seam. Append the primary key to make the sort total, and compare as a tuple (row value) so the boundary is exact.
- Encode the cursor opaquely and completely. Return an opaque token (base64 of the sort-key tuple), not a raw offset, so clients cannot fabricate positions and you can evolve the shape later. Include every column the ORDER BY uses; a cursor missing the tiebreaker cannot seek correctly.
- Match the index to the sort exactly. The composite index must cover the ORDER BY columns in the same order and direction, or the database sorts on the fly and the seek advantage is lost. Verify the plan uses an index scan, not a sort node above it.
- Give up offset-only features honestly. Keyset offers next and previous,
not jump-to-page-500 or an exact total; a full
COUNT(*)on a large table is its own scan. Offer next-page and an estimated count, or keep offset only for shallow admin views where depth is bounded.
Signals
- Does
EXPLAINshow constant rows scanned per page regardless of depth? - Is the sort key unique, or backed by a tiebreaker that makes it total?
- Does the cursor encode every ORDER BY column and resist client tampering?
- Does the index match the sort's columns and direction so no extra sort runs?
Boundaries
This is about page-fetch cost and cursor correctness. General index and query tuning is sql-optimization; caching hot first pages is caching-strategy. Jump-to-arbitrary-page and exact live totals are product trade-offs keyset deliberately gives up, not defects to fix here.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.