-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[8.x] Improve one-of-many performance #37451
Conversation
So, won't |
@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 |
So are the constraints added to both the sub query and the "main" query? |
@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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This order should not have changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I guessed that types are ordered by probability. Just noticed the laravel docs show this exact example.
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,000
users and100,000
logins.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 usingbeforeQuery
introduced 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
getRestrictionQuery
method 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