mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
Significant performance degradation with enable_lazy_ghost_objects: true
#7261
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 @javer on GitHub (Nov 25, 2023).
Bug Report
Summary
After updating ORM from 2.15.2 to 2.17.1 and turning on
enable_lazy_ghost_objectsas it's suggested I've noticed a significant performance degradation during test suite running. The overall suite became slower by noticeable 30%. Localizing the slow spot I've found that ProxyReferenceRepository::load() now takes 50 seconds in total instead of the previous 3.86 seconds, i.e. became 13x slower.Tracking down
ProxyReferenceRepository::load()->ProxyReferenceRepository::unserialize()I've found thatEntityManager::getReference()became 23x slower (2.055 seconds -> 47.888 seconds in total). This real project has hundreds of entities and complex relations between them. During running test suite with 1k+ scenarios a lot of fixtures are generated, saved and loaded (including references):I've created a test command to reproduce the issue, and running it in the same project I get:
I've created a small reproducer: https://github.com/javer/doctrine-orm-lazy-ghost
It's a fresh Symfony 6.3 project with one additional commit:
36a3e20b93Running
bin/console app:test:ormI have the following results:Slowdown numbers are not so high as in a real project, but there is only one simple entity without any relations, and no save/load operations, only getting references. Even in this simple case
ProxyFactory::getProxy()slowdown by almost 4x is too expensive for usingenable_lazy_ghost_objects.Taking into account that
enable_lazy_ghost_objectswill be alwaystruein ORM 3.0 I think it's worth fixing it.How to reproduce
Expected behavior
Turning on
enable_lazy_ghost_objectsshouldn't have a noticeable impact on the performance.@derrabus commented on GitHub (Nov 25, 2023):
cc @nicolas-grekas
@michnovka commented on GitHub (Feb 12, 2024):
Has anybody else managed to reproduce this issue?
@marforon commented on GitHub (Feb 21, 2024):
Yes, it's drawn back for us to upgrade; this represents a significant performance degradation.
@rrehbein commented on GitHub (Feb 21, 2024):
Starting from the reproduction instructions javar left of:
Run on an AWS EC2 AL2023 c5.large with php version:
Results:
Reproduction code after SF6.4 update:
Reproduction code after ORM v3 upgrade:
Other project:
@beberlei commented on GitHub (Feb 22, 2024):
Here is a screenshot of a compare callgraph in Tideways Profiler, it shows the relevant parts that are slow:
The overall slowdown is roughly in line what @rrehbein reported.
I will take a deeper look when i have more time.
@beberlei commented on GitHub (Feb 25, 2024):
I looked at createLazyGhost factory method and found that it acts both as an initializer when invoked the first time, and then as a factory for lazy ghosts. It seems when the initializer code is run every time as well, this causes a lot of wasted CPU and allocated memory. A simple attempt to split both methods up cut 50% of the slowdown:
I hardcoded it into my doctrine/orm and symfony/var_exporter components of @javer testproject. So no nice diff, the changed lines are here: https://gist.github.com/beberlei/97899ea7ce4261502a6df1300ab9f181
This would require var-exporter to add these new methods, so I am looking to find a simpler fix that cuts the time and memory in createLazyGhost already.
@nicolas-grekas commented on GitHub (Mar 9, 2024):
This patch saves a lot of time by not creating a closure in a loop. Note that this change breaks tests so it's not the correct one but that might give some ideas :
@nicolas-grekas commented on GitHub (Mar 9, 2024):
@beberlei don't mind sharing a reproducer with vendor/ committed and I might be able dig your ideas also.
@nicolas-grekas commented on GitHub (Mar 9, 2024):
IIUC, most of your gain @beberlei can be achieved by this patch, isn't it?
@nicolas-grekas commented on GitHub (Mar 13, 2024):
Below is a better patch for the ORM side. Together with this one https://github.com/symfony/symfony/pull/54253, I get the following stats on my machine:
Locally, I also have a native proxy implementation for php-src (I need to write an RFC about it), and with it, I get 3.27s with the current API and implementation. That's good food for thoughts on my side to move this RFC forward :)
Here is the Blackfire.io comparison between disabled and patched lazy-ghosts:
https://blackfire.io/profiles/compare/4561cec4-97af-4c40-a180-ee5745ca8119/graph
The patch for ProxyFactory.php
@michnovka commented on GitHub (Mar 13, 2024):
Is the goal to get to the same or better performance than with lazyghosts disabled or is this considered "good enough" result?
@nicolas-grekas commented on GitHub (Mar 13, 2024):
This is good enough to me. The core issue with the current code is the initializer closure that creates a self-reference in the object graph, which adds a lot of pressure on the garbage collector. The other changes are minor perf optim that shouldn't matter much in practice.
Note that we're comparing two widely different set of proxies. The legacy proxy system has many serious limitations.
@beberlei commented on GitHub (Mar 13, 2024):
@nicolas-grekas does your change here require the symfony change or are they independent?
The improvement is good enough for me too for now.
@nicolas-grekas commented on GitHub (Mar 14, 2024):
The patch are independent. BUT the ORM patch makes the test suite fail on one or two test cases which we need to investigate.
@Tristan971 commented on GitHub (Mar 22, 2024):
I don't doubt that the new setup is better, and I'm sure eventually it will catch up, but right now we're seeing the same results as you outline in https://github.com/doctrine/orm/issues/11087#issuecomment-1994002826, so losing half the performance (from 17s to 29s for setting up a subset of test fixtures).
That's many times better than before your patch, of course, but still a fairly high cost... I hope the issue keeps getting some attention until we're in a closer performance range.
EDIT: turns out I was comparing on 2.19.2 which lacks the patch; using 2.19.3 seems to fix the issue entirely for our use-case (at least with synthetic loads, we'll have to compare for real load).
@nicolas-grekas commented on GitHub (Mar 23, 2024):
Good news!
We can close this issue then :)
@greg0ire commented on GitHub (Mar 23, 2024):
Let's! Thanks @nicolas-grekas !
@Tristan971 commented on GitHub (Mar 23, 2024):
For what it's worth, we also see no performance difference at all after deploying to our production:

So I can only agree with the decision to close it 👍
@javer commented on GitHub (Mar 25, 2024):
I can confirm that after upgrading to doctrine/orm 2.19.3 turning on
enable_lazy_ghost_objectsmakes the initial test suite slower only by negligible 5%.Thank you very much @beberlei and @nicolas-grekas !
@Reinhard-Berger commented on GitHub (Oct 14, 2025):
should a goal not to be slower than before?
@greg0ire commented on GitHub (Oct 14, 2025):
Maybe, maybe not, right now you should be using native lazy objects, so this thread is no longer very interesting.