Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Snapey's avatar
Level 122

Beware pagination with offset

I ran into an issue this morning, which I cannot see anything online about it (maybe I have not found the right search terms yet) so posting here incase it helps someone in the future.

Imagine you have a mysql database with 30 or so events. The events each have a date field. The paginated eloquent query might look like;

$events = Event::where('course_id',$course->id)->orderBy('date', 'ASC')->paginate(10);

This all appears to work fine

Now suppose there are two events that have the same date, and these two records just happen to be records 10 and 11 in the total recordset. However, since they both have the same date, its up to the database to decide which record to show first when the order by is ambiguous.

So now we load page 1 and get records 1 through 10 (all ok)

Now we load page 2, and the pagination uses limit 10 and offset 10

We could reasonably expect to get records 11 through 20, but for some reason the database evaluates the records in a different order and instead outputs records 10,12,13.... 20

So, record 10 is output on page 2 (as well as page 1), and record 11 is never displayed.

The answer is quite simple and that is to make sure there is no ambiguity in the search order by adding an additional, unique, orderBy;

$events = Event::where('course_id',$course->id)->orderBy('date', 'ASC')->orderBy('id','ASC')->paginate(10);

If anyone has any links or has experienced this issue, please feel free to contribute.

0 likes
6 replies
LaryAI's avatar
Level 58

The issue described in the question occurs when there are multiple records with the same date and the pagination uses the offset parameter. In such cases, the database may evaluate the records in a different order, resulting in incorrect pagination.

To solve this issue, you can add an additional, unique orderBy clause to ensure there is no ambiguity in the search order. In this case, you can order by the id column in ascending order.

Here's the updated code:

$events = Event::where('course_id', $course->id)
    ->orderBy('date', 'ASC')
    ->orderBy('id', 'ASC')
    ->paginate(10);

By adding the orderBy('id', 'ASC') clause, you ensure that the records are ordered by the id column in ascending order, which guarantees a consistent order even when there are multiple records with the same date.

This solution should resolve the issue and ensure correct pagination.

Snapey's avatar
Level 122

Lary, its like you read my mind.... or just read my post and blerked it back out again.

4 likes
tykus's avatar
tykus
Best Answer
Level 104

Yes, the ordering of the original query was non-deterministic, so more columns were necessary.

If multiple rows have identical values in the ORDER BY columns, the server is free to return those rows in any order, and may do so differently depending on the overall execution plan. In other words, the sort order of those rows is nondeterministic with respect to the nonordered columns

https://dev.mysql.com/doc/refman/8.0/en/limit-optimization.html

Snapey's avatar
Level 122

@tykus "non-deterministic" - I knew there was a better term than ambiguous because that is found in lots of discussions regarding joins.

Please or to participate in this conversation.