-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
[GH-1569] Optimize eager fetch for collections to batch query #8391
[GH-1569] Optimize eager fetch for collections to batch query #8391
Conversation
9b54e08
to
e63d416
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as abuse.
This comment was marked as abuse.
This comment was marked as spam.
This comment was marked as spam.
To summarize the suggested changes with my own words, this hooks into the place where entitites are being created during hydration. Thus, it sees all "new" entities, i. e. at the are first re-created from database values. It tracks all those entities and their one-to-many (also many-to-many?) collections that are configured with After the entities have been loaded, for every such collection a new query is performed through the target (referred-to) entity class' Then, loop over all those entities and add them to their respective collections to initialize those. Not sure if |
@beberlei Given your experience writing tricky solutions using subselects and doing AST manipulations like the Paginator component does, do you think it would be possible to write a helper component that could provide this feature and be used to do the "context sensitive optimization"? I also have the "multi-step hydration" explained at https://ocramius.github.io/blog/doctrine-orm-optimization-hydration/ in mind. Idea along the lines of: // Assume User has to-many association to Address in User::$addresses
$query = $entityManager->createQuery('SELECT u FROM ' . User::class . ' u WHERE ...');
$result = $query->getResult();
InitializeCollection::for($query, 'u.addresses'); What this would be supposed to do:
Might be more tricky to get right with composite primary keys? |
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as resolved.
This comment was marked as resolved.
…ions. Co-authored-by: Wouter M. van Vliet <wouter@interpotential.com>
e63d416
to
dc899e2
Compare
Is there a technical reason to disallow this? Would it not still be benefical to fetch even has one associations in it's own query when the cardinality of the target entity is much lower to avoid fetching duplicated data? |
@JanTvrdik yes, but that is what fetch=EAGER does for to one already, either by doing a join, or by triggering all laods at once. |
Thanks @beberlei ! |
@@ -1047,7 +1047,9 @@ public function walkJoinAssociationDeclaration($joinAssociationDeclaration, $joi | |||
} | |||
} | |||
|
|||
$targetTableJoin = null; | |||
if ($relation['fetch'] === ClassMetadata::FETCH_EAGER && $condExpr !== null) { | |||
throw QueryException::eagerFetchJoinWithNotAllowed($assoc['sourceEntity'], $assoc['fieldName']); |
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.
Hi, I probably have a poor implementation or use of eager mode on my relationships but this exception creates a BC break on my side.
Maybe it should be replaced by a deprecation pointing to this ticket : #10978 to explain why this is a bad pratice ?
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.
Indeed this is a BC in v2... How was it not been cached before merging? :(
Fetch EAGER mode ignores orderBy as of changes introduced with doctrine#8391 Fixes duplicated doctrine#11381
Fetch EAGER mode ignores orderBy as of changes introduced with doctrine#8391 Fixes duplicated doctrine#11381
Fetch EAGER mode ignores orderBy as of changes introduced with doctrine#8391 Fixes duplicated doctrine#11381
Fetch EAGER mode ignores orderBy as of changes introduced with doctrine#8391 Fixes duplicated doctrine#11381
EAGER fetch mode ignores orderBy as of changes introduced with doctrine#8391 Fixes doctrine#11163 Fixes doctrine#11381
@@ -1264,7 +1264,7 @@ protected function getSelectColumnsSQL() | |||
} | |||
|
|||
$isAssocToOneInverseSide = $assoc['type'] & ClassMetadata::TO_ONE && ! $assoc['isOwningSide']; | |||
$isAssocFromOneEager = $assoc['type'] !== ClassMetadata::MANY_TO_MANY && $assoc['fetch'] === ClassMetadata::FETCH_EAGER; |
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.
What is the reason for this change?
This supersedes and adjusts #1569 to current Doctrine 2.17 branch.
When you configure a one-to-many collection to be
fetch=EAGER
, then instead of immediately loading all collections it batches the fetch operation at the end by selecting all entities for all collections. Collections are loaded in batches of 100, configurable byConfiguration::setEagerFetchBatchSize
.Changing the collection fetch mode can be done on a per query basis with
$query->setFetchMode('rootEntity', 'association', ClassMetadata::FETCH_EAGER);
. This can be done as an alternative to fetch join collection valued associations.Open points:
Fixes #4762