-
-
Notifications
You must be signed in to change notification settings - Fork 849
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
Updates regarding doctrine performances with associations #717
Conversation
891f884
to
bc1406a
Compare
@@ -354,4 +367,21 @@ private function normalizeValues(array $values) : array | |||
|
|||
return array_values($values); | |||
} | |||
|
|||
private function hasJoin($queryBuilder, $alias, $association) |
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.
Missing type hints.
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.
By the way I think getJoin
returning null
when the join doesn't exist would be a cleaner API.
Great improvements! |
bc1406a
to
3f79227
Compare
|
||
//@TODO useless at the moment, but Doctrine queries non-necessary relations because addSelect($associationAlias) lazy fetch every association | ||
//By using this array of properties, it Lazy fetch association, which are initially in an INNER JOIN (fetches them twice ?!) | ||
//If I try to use associationAlias when it has every property, but the properties array when it doesn't it fails because it can not fetch parent association |
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 is still an issue, @Simperfit mind taking a look? I think you've a good background with Doctrine maybe you can help figuring this out :/.
2fa9acd
to
04fab64
Compare
// | ||
//By using this array of properties, Doctrine will lazy fetch every associations, which are initially in an INNER JOIN (fetches them twice ?!) | ||
//If I try to use associationAlias when it has every property (so that Doctrine does not do sub queries on top of the initial one) it fails because it can not fetch parent association (like internally they try to find aliasX, but no aliasX is selected, we've instead aliasX.id, aliasX.name) | ||
//I obviously tried to specify `WITH` `aliasX.id = aliasY.id` without success | ||
foreach ($this->getMetadataProperties($mapping['targetEntity']) as $property => $propertyMetadata) { |
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.
Please read my story, if you have any clue or idea to help me think it'd be wonderful :D. ping @Simperfit
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.
e5570a2
to
179399d
Compare
@@ -131,16 +131,16 @@ public function testApplyToItem() | |||
$classMetadataProphecy->getAssociationNames()->shouldBeCalled()->willReturn([0 => 'relatedDummy', 'relatedDummy2']); | |||
$classMetadataProphecy->associationMappings = [ | |||
'relatedDummy' => [ | |||
'fetch' => 3, 'joinColumns' => [['nullable' => true]], 'targetEntity' => DummyRelated::class | |||
'fetch' => 3, 'joinColumns' => [['nullable' => true]], 'targetEntity' => DummyRelated::class, |
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.
1 on each line please...
Ready for review :D ! This improves the complex queries a lot! Strong impact on performances, mainly on collections with lots of related fields (almost counts in seconds). |
* | ||
* @return string the new association alias | ||
*/ | ||
protected function addJoinOnce($queryBuilder, $queryNameGenerator, $alias, $association): string |
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.
Why protected
?
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.
Missing typehints btw
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.
Protected because it's called from filters (ie SearchFilter
).
52e93dd
to
20e380e
Compare
Is it ready to be merged? |
Apart from my comment on query hint it's good to go. |
|
||
$queryBuilder->addSelect(sprintf('partial %s.{%s}', $associationAlias, implode(',', $select))); | ||
|
||
$relationAlias = $relationAlias.++$j; |
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.
is there any reason that $j could not be $nbOfJoin or smth like that. IMO it's not that clear
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.
Yeah it's not really the number of join, it's a way to keep the alias unique across relation, ie a random number.
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.
We should avoid random numbers in DQL as much as possible to trigger the Doctrine cache as often as possible.
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.
It's the same in every query ofc. Just giving a explanation to the simple variable name.
@soyuka Amazing work ;) |
140ade9
to
d31b39f
Compare
@dunglas I added a decoration possibility, not sure if I have to catch an undefined method call though. Should I add the same for the ItemDataProvider? Should I add an interface to be implemented by decorators using |
d31b39f
to
7bb1ca1
Compare
62832fd
to
ba129bc
Compare
Done thanks. I've added the same on |
98b82ff
to
6568143
Compare
What I don't like with this interface is that it expects the query to return a result. For example, if you wanted to use the |
6568143
to
4f21a05
Compare
But for such cases, decoration can be used (decorating the |
Indeed, this is what I was going to say. For example: /**
* {@inheritdoc}
*/
public function getResult(QueryBuilder $queryBuilder)
{
$query = $queryBuilder->getQuery();
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
$doctrineOrmPaginator = new DoctrineOrmPaginator($query, $this->useFetchJoinCollection($queryBuilder));
$doctrineOrmPaginator->setUseOutputWalkers($this->useOutputWalkers($queryBuilder));
return new Paginator($doctrineOrmPaginator);
} |
4f21a05
to
583d234
Compare
Wait for tests to pass and to me it's good to go. |
So, can you revert the last commit introducing the |
* @param string $alias | ||
* @param string $association the association field | ||
* | ||
* @return Doctrine\ORM\Query\Expr\Join|null |
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.
Can you add a use
statement instead?
583d234
to
430a714
Compare
430a714
to
3b2ebd6
Compare
- use innerJoin when possible (relation is not nullable) - use partial selects and skip unreadable properties - improve coverage
3b2ebd6
to
ebf4735
Compare
Thanks @soyuka |
Updates regarding doctrine performances with associations
EagerLoadingExtension
+SearchFilter
) (tested)EagerLoadingExtension
(tested)Query::HINT_FORCE_PARTIAL_LOAD
to avoid fetching OneToOne relations when we don't need them