October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

Pagination at Page 500: Why It Slows Down and How to Stop Duplicate Rows

Deep offsets can cost more because skipped rows still need processing. Repeated or missing rows often point to unstable ordering, changing data, joins, or application handling—not OFFSET alone.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A slow 500th page and repeated rows often have different causes. A large OFFSET can make a query slower because the database still has to compute rows it will skip. Duplicate or missing rows can result when page boundaries rely on a non-unique or changing order, though joins and application logic can also duplicate results. Use a deterministic order with a unique tie-breaker first; consider keyset pagination when people browse large result sets sequentially.

Why can page 500 be slow?

With offset pagination, the application asks the database to skip a number of rows and return the next batch. PostgreSQL cautions that skipped rows still have to be computed inside the server, so a large offset may be inefficient. Django likewise notes that requests for high page numbers can be slow on large QuerySets.

As an Amazon Associate I earn from qualifying purchases.

For example, a page size of 50 means page 500 starts after 24,950 rows. The database may need to process those preceding rows before returning the requested 50. The actual cost depends on the query, indexes, data, and execution plan; the page number alone does not establish a particular delay or a universal threshold. PostgreSQL 17: LIMIT and OFFSET · Django: Paginator

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why do rows repeat or disappear between pages?

The sort order does not uniquely identify rows

LIMIT and OFFSET do not define which rows come first. PostgreSQL advises using an ORDER BY that constrains results to a unique order; without it, the selected subset can be unpredictable. Sorting only by a field such as created_at is not enough when multiple rows share that value: their relative order is not guaranteed.

Add a unique tie-breaker, typically the primary key. For a descending chronological feed, ORDER BY created_at DESC, id DESC gives each row a distinct position if id is unique. Django also recommends ordering a QuerySet for consistent pagination. PostgreSQL 17: LIMIT and OFFSET · Django: QuerySet API reference · Django: Paginator

The data changes between requests

Offset pages are usually separate queries. If rows are inserted or updated so they move before a later page’s offset, the next query can have shifted boundaries: a row may appear again, or another may be missed. This is a possible consequence of paging through changing data, not proof that every duplicate is caused by OFFSET.

The query or application duplicates entities

Check whether joins produce multiple result rows for one entity, whether the query’s filters and grouping match the intended result, and whether application code appends or merges rows more than once. A stable sort fixes ordering ambiguity; it does not remove duplicates that the query or application already creates.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make offset pagination deterministic

Before changing pagination strategy, specify a stable order that ends in a unique key, then inspect the actual query and results. For example:

SELECT id, created_at, payload
FROM items
ORDER BY created_at DESC, id DESC
LIMIT 50 OFFSET 24950;

This pattern assumes the ordered columns and their null behavior make sense for the application. Confirm the generated SQL, joins, filters, and query plan rather than assuming a tie-breaker alone will make the query fast.

When keyset pagination helps

Keyset, or cursor, pagination continues from the last row’s ordered values instead of asking the database to skip every preceding row. It can avoid deep-offset work when the ordering and query support efficient continuation. It is a better fit for next/previous browsing through a large feed than for jumping directly to an arbitrary numbered page.

For the same descending order, the continuation query can look like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
SELECT id, created_at, payload
FROM items
WHERE (created_at, id) < (:last_created_at, :last_id)
ORDER BY created_at DESC, id DESC
LIMIT 50;

The cursor values are those of the last row returned on the previous page. This is an implementation sketch, not a drop-in query for every database: tuple comparisons, sort directions, and NULL handling vary. Build a predicate that matches the exact ordering and verify its plan. An index aligned with the query can matter; Django REST framework recommends an index on the cursor ordering field. Its guidance also favors a stable, non-null, non-float ordering field that is unique or nearly unique. If the field is not unique, account for a unique tie-breaker. Django REST framework: Pagination

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Offset or keyset: which fits?

Decision Offset pagination Keyset/cursor pagination
Deep pages Large offsets may be inefficient because skipped rows still have to be computed. Can avoid deep-offset work when the continuation query and ordering are efficient.
Navigation Maps naturally to numbered pages and direct jumps. Typically supports forward or backward traversal, not arbitrary page-number jumps in the documented Django REST framework cursor paginator.
Ordering Needs a deterministic order; a unique combined order avoids unpredictable subsets. Needs a stable ordering represented by the cursor; ties require careful handling.
Changes during paging Inserts or updates before a later offset can shift page boundaries across requests. Django REST framework says properly used cursor pagination can avoid showing the same item twice when other clients insert rows during paging.
Implementation Straightforward for numbered-page interfaces. Requires cursor handling and care over supported sort fields and continuation predicates.

Keep offset pagination when numbered jumps matter and measured performance is acceptable. For a large sequential feed, keyset pagination may be a better fit. Anchor or checkpoint designs can preserve some jump-like behavior, but add complexity and should be justified by a real product requirement. Neither strategy is universally faster: measure representative queries and inspect their plans before promising a speedup.

How to diagnose the specific symptom

  1. Inspect the generated SQL. Confirm the actual ORDER BY, filters, joins, grouping, limit, and offset or cursor predicate.
  2. Make ordering unique. Add a unique tie-breaker after the user-visible sort field and verify that null values and sort directions are handled consistently.
  3. Check whether the result itself has duplicates. Compare entity IDs in the raw query result with the rows rendered by the application to distinguish query-level duplication from pagination-boundary changes.
  4. Consider concurrent writes. Repeat the page requests against a stable dataset if possible, then compare with requests while inserts or updates occur.
  5. Measure the query plan. Test the actual workload and indexes at representative page depths. Documentation describes general behavior, not a benchmark or guaranteed improvement for your application.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.