mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
Avoid Using unqualifed COUNT in EntityPersister #7163
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Aweptimum on GitHub (Jun 6, 2023).
Feature Request
Summary
Might be a dupe of #5960
Using Symfony. I switched from using
findBytomatchingin my services. I then checked the profiler for an unrelated feature I was working on and noticed Doctrine was issuing aCOUNT (*)query. That's a bit concerning for larger tables, so I dug into the code and traced it togetCountSql3827dd769e/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php (L1136-L1156)If the $criteria is a Criteria object and doesn't have any expressions, this will issue a count against the entire table. I think to help avoid this, it should check if maxResults is set like so (rough example):
I don't know if that check could go in one of the helper methods used in here, but it would save some io when the actual result set is bigger than the given limit.
@greg0ire commented on GitHub (Jun 6, 2023):
Does it break any unit tests where you try that? Maybe that will help us understand why it's not as you describe in the first place.
@Aweptimum commented on GitHub (Jun 6, 2023):
I just made a fork, cloned it + ran composer install, and ran vendor/bin/phpunit on the 2.15 branch. Here's the result:
Tests: 3746, Assertions: 7031, Errors: 1452, Failures: 11, Skipped: 102, Incomplete: 2.
Then made my change:
Tests: 3746, Assertions: 7031, Errors: 1452, Failures: 11, Skipped: 102, Incomplete: 2.
It's identical, but what is causing all these errors .-.oops forgot to enable sqlite drivers in .ini@Aweptimum commented on GitHub (Jun 6, 2023):
No the change doesn't break anything
Without change:
OK, but incomplete, skipped, or risky tests!
Tests: 3735, Assertions: 13316, Skipped: 73, Incomplete: 2.
With change:
OK, but incomplete, skipped, or risky tests!
Tests: 3735, Assertions: 13316, Skipped: 73, Incomplete: 2.
@greg0ire commented on GitHub (Jun 6, 2023):
Ok, so it's not deliberately like that, so maybe we are not missing anything. Consider sending a pull requests with tests then.
@Aweptimum commented on GitHub (Jun 6, 2023):
Done, if you want me to make any changes let me know :)
@greg0ire commented on GitHub (Jun 7, 2023):
Let's backtrack a bit. What calls
getCountSqland why?@Aweptimum commented on GitHub (Jun 7, 2023):
Oh, yes, I probably should have elaborated on that more. the repository's
matchingmethod returns an instance of AbstractLazyCollection (LazyCriteriaCollection in this case). I was checking if the collection was empty, usingisEmpty, and thought that it might have something to do with that. Looking through most of the methods in AbstractLazyCollection, they all check if the collection is in an initialized state first. If not, they callinitialize, which calls the abstractdoInitialize. In LazyCriteriaCollection,doInitializeasks its entityPersister to load the collection.However, the overridden methods in LazyCriteriaCollection don't call
initialize, they instead check if the collection is in an initialized state and will grab a cached value if so. If not, they delegate to the entity persister which retrieves the value through a query.isEmptyjust delegates tocount, and the problem is that it's one such overridden method and ends up callinggetCountSqlif it isn't in an initialized state.countcallsentityPersister->count(), which callsentityPersister->getCountSqlpassing in the LazyCriteraCollection's $criteria property as the parameter. As mentioned, it counts all records that meet the criteria regardless of maxResults.This is all that's needed to trigger that call stack:
The weird part is that the AbstractLazyCollection's count method has the behavior i want - it just returns the count of the loaded elements in the ArrayCollection after initialization.
But now that I've gone through it more, it looks like if I can get LazyCriteriaCollection to trigger its initialize function, it'll return the count of the loaded elements - not the count query (line 52):
3827dd769e/lib/Doctrine/ORM/LazyCriteriaCollection.php (L50-L62)I might just be able to call
toArray, count that, and call it a day.Edit: Yeah, calling
toArraydoes not trigger a COUNT(*), so there's my workaround. I guess this issue can be closed.@Aweptimum commented on GitHub (Jun 7, 2023):
I do still find it weird that the same method can return different values depending on the load state of the collection
@greg0ire commented on GitHub (Jun 7, 2023):
That's already reported here: https://github.com/doctrine/orm/issues/9951, so let's close.
@Aweptimum commented on GitHub (Jun 7, 2023):
Fair enough, sorry if this was a massive waste of time.
@greg0ire commented on GitHub (Jun 7, 2023):
Again, no worries, just… make sure to get all the sleep you need 😉