[8.x] Improve one-of-many performance - #37451
#37451Merged
taylorotwell merged 8 commits intoMay 21, 2021
Merged
Conversation
driesvints
reviewed
May 21, 2021
Member
|
So, won't |
Contributor
Author
|
@taylorotwell It is called by the constructor, however at that point it doesnt know that the relationship is one-of-many so it must be called again when |
Member
|
So are the constraints added to both the sub query and the "main" query? |
Contributor
Author
|
@taylorotwell yes, but that does not effect the performance or the results at all, so not necessary to remove the constraint from the parent builder. |
| * @param \Closure|string|null $column | ||
| * @param string|null $relation | ||
| * @param string|null $column | ||
| * @param string|\Closure|null $aggregate |
Collaborator
There was a problem hiding this comment.
This order should not have changed.
Contributor
Author
There was a problem hiding this comment.
Okay, I guessed that types are ordered by probability. Just noticed the laravel docs show this exact example.
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.
Background
Eager loading one-of-many relationships can become slow for big tables.
Solution
When eager loading, the related models are loaded using
WHERE foreign_id in (1,2,3,...), currently this constraint is applied to the parent query in one of many relationships:This means that the subselect query gets
MAX(id)rows for every group in the table, not only the required ones.This can be improved by adding the constraint to the subquery:
See the `EXPLAIN ANALYZE` results for both queries for more information...
Results for
4,000users and100,000logins.Filter rows on parent query:
Filter rows on subquery:
How It Works
The subquery is bound to the class property
$oneOfManySubQuery, the constraints to restrict rows by the foreign_key when eager loading or retrieving a single result will be added to this sub query builder. The subquery will be added to the inner join usingbeforeQueryintroduced in #37431More details...
A new public method is added to retrieve the one of many subquery builder instance:
framework/src/Illuminate/Contracts/Database/Eloquent/SupportsPartialRelations.php
Line 29 in e16066d
The
getRestrictionQuerymethod decides which query foreign key constraints should be added to:framework/src/Illuminate/Database/Eloquent/Relations/Relation.php
Lines 374 to 377 in e16066d
framework/src/Illuminate/Database/Eloquent/Relations/Concerns/CanBeOneOfMany.php
Lines 221 to 226 in e16066d
ping #37362