mirror of
https://github.com/doctrine/orm.git
synced 2026-03-24 06:52:09 +01:00
[PR #10035] Optimize Object Hydration performance on large result sets #12048
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?
Original Pull Request: https://github.com/doctrine/orm/pull/10035
State: closed
Merged: No
Hi folks!
While assessing a client's project performance I found some optimizations regarding the ORM hydration process that improves speed when working with large result sets and collections.
Expand to get some context on how we reached this.
The context is about online carts on a B2B e-commerce platform with a high number of items and complex personalization logic. We reached the point in the optimization process where most of the time was spent in the ORM (after serialization) when fetching a cart.This makes sense because of the volume and the logic at stake.
Denormalization or caching does not make sense for us because of the low read/write ratio and the business logic involved so we first went with the 2-step hydration technic.
While analyzing profiling results we more or less came to the same conclusion as #8390: the hydration process converts data over and over again even if the entity is already hydrated>
But after trying to work around performance for specific DBAL types that were costly to convert (namely Symfony's UUID and Dunglas's JSON document) and digging deeper into profiles I concluded something could be done directly in the Hydrator for the benefit of everyone instead of writing our specific optimized hydrator:

This PR acts according to one consideration: most parts of the hydration process are not slow per se but are repeated for every row and column. By applying some small optimizations, moving some code before the first iteration, or some code at the very last moment, we can improve the overall process.
The more rows and columns, the more the process is accelerated.
For examples:
With this patch, I manage to reach the following results:
->getQuery()->getResult()Doctrine\ORM\PersistentCollection::*TypedNoDefaultReflectionProperty::getValueDoctrine\ORM\Internal\Hydration\AbstractHydrator::resultSetMappingDoctrine\ORM\Internal\Hydration\AbstractHydrator::hydrateColumnInfoDoctrine\DBAL\Types\IntegerType::convertToPHPValueDoctrine\DBAL\Types\StringType::convertToPHPValueDoctrine\DBAL\Types\BooleanType::convertToPHPValueDoctrine\DBAL\Types\DateTimeImmutableType::convertToPHPValueApp\DBAL\Types\UuidType::convertToPHPValueI hope we can manage to get this work so that everyone enjoys better performance 🤗
If you are willing to move in this direction, we can probably adapt ArrayHydrator the same way.