Repository navigation
[6.x] Work search results out once when paginating - #15889
Merged
jasonvarga merged 1 commit intoNov 13, 2026
Merged
Conversation
…n combining wheres
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Paginating search results works the results out twice, and combining two or more
wheres on them compares every result with every other.Both are in
IteratorBuilder, which the search query builder extends:paginate()callsgetCountForPagination()and thenget(), and each one fetches and filters the items again. For search that means turning every hit into an entry, term or asset twice, whatever the page size.whereafter the first is combined with the ones before it byintersectItems(), which asks$filteredEntries->contains($entry)for every item. That's a loose comparison of each object against each of the others.{{ search:results }}always adds astatuswhere, and asiteone on a multi-site, so it's the usual case rather than an unusual one.paginate()now works the filtered items out once and uses them for both the total and the page.intersectItems()looks objects up byspl_object_id(); both sides are always taken from the same original items, so it's the same answer. Anything that isn't an object is compared as before.Numbers
A local (Comb) index, a query with 1,022 hits,
where('status', 'published')->where('site', 'en'), each in a fresh process:get()paginate(10)The second cost grows with the square of the number of hits, so the gap widens on bigger result sets.
Tests
Paginating asks for the search results once and gives the right total and page with two wheres (fails without the change), and a query can be added to and used again after paginating.