Skip to content

[6.x] Skip empty-list lookups in the Entries fieldtype and Stache whereIn" - #15879

Merged
jasonvarga merged 6 commits into
statamic:6.xfrom
DanielDarrenJones:perf/6x-empty-relationship-queries
Nov 13, 2026
Merged

jasonvarga merged 6 commits into
statamic:6.xfrom
DanielDarrenJones:perf/6x-empty-relationship-queries

Conversation

@DanielDarrenJones

@DanielDarrenJones DanielDarrenJones commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

A listing column for an entries field runs two queries for every row, even when the row has nothing selected. The value becomes whereIn('id', []), which can't match anything, but each of the two queries still tests every id in every collection before finding that out. On a listing where most rows leave the field empty, that is most of the request.

  • Fieldtypes\Entries::getItemsForPreProcessIndex() returns an empty collection when nothing is selected, without building a query.
  • Stache\Query\Builder::filterWhereIn() returns nothing for an empty list without testing each value. An orWhereIn with an empty list still leaves the rest of the query alone, and whereNotIn is untouched.

augment() is unchanged, so a template still gets a query builder for an empty field.

Benchmark

Against 6.x at 9d20aef, PHP 8.5, file cache store. A Control Panel listing of 50 entries with an entries-field column, in a collection where 62 of the 64 entries have nothing selected. One PHP process per request, three rounds of ten, alternating.

6.x This PR
CP entries listing 122.6 ms 72.7 ms −41%

A listing whose rows all have something selected doesn't change.

Checked

Every page and Control Panel response of the benchmark site, the contents of 136 indexes and the ids returned by 44 queries are byte-identical to 6.x.

The first change is in the fieldtype, so it applies whichever driver stores the entries. The second is the Stache's own builder.

Tests

  • nothing is found in an empty list, for id and for another field; orWhereIn with an empty list keeps what the first where found; whereNotIn with an empty list finds everything;
  • pre-processing an entries field for a listing returns an empty collection for null and for [].

They pass on 6.x without this change.

DanielDarrenJones and others added 6 commits November 12, 2026 23:38
A listing column for an entries field with nothing selected ran two queries across every collection for whereIn('id', []), which can't match. Nothing is looked for when nothing is selected, and a where in an empty list no longer tests every value in the index.
whereIn('id', [...]) tested every id in every collection to find one or two. An entry's key in its collection's id index is its id, so the ones asked for are picked out directly, in the order the index holds them. If any aren't found that way the query filters as before, since ids are compared without regard to case.
…ship-queries

# Conflicts:
#	src/Fieldtypes/Entries.php
#	tests/Data/Entries/EntryQueryBuilderTest.php
@jasonvarga jasonvarga changed the title [6.x] Don't query for the entries of an empty relationship field [6.x] Skip the entries lookup for an empty entries field Nov 13, 2026
@jasonvarga jasonvarga changed the title [6.x] Skip the entries lookup for an empty entries field [6.x] Skip empty-list lookups in the Entries fieldtype and Stache whereIn" Nov 13, 2026
@jasonvarga

Copy link
Copy Markdown
Member

Since merging #15890, this PR's performance improvement benchmarks is probably less. Still merging anyway.

@jasonvarga
jasonvarga merged commit ab4f235 into statamic:6.x Nov 13, 2026
63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants