Performance
This content is for v1.0. Switch to the latest version for up-to-date documentation.
Understand the runtime behavior that matters once your usage moves beyond small CRUD flows.
Identity map
Section titled “Identity map”EntityManager keeps an in-memory identity map. Loading the same entity class and primary key twice returns the same PHP object instance until the manager is cleared.
This avoids duplicate objects for the same row, but it also means long-running imports should clear the manager periodically.
Result cache
Section titled “Result cache”$qb->enableResultCache($lifetime, $cacheId);Result cache stores query results. Locked queries are never cached.
Second-level cache
Section titled “Second-level cache”$em = new EntityManager($connection, secondLevelCache: $pool);Second-level cache stores raw entity row data for find() lookups by entity class and primary key. It survives EntityManager::clear(), unlike the identity map.
When a flush updates, deletes, or soft-deletes an entity, Articulate evicts cache entries for every mapped entity class that shares the same table and primary key — keeping same-row projections consistent after writes.
Query logging
Section titled “Query logging”Implement QueryLoggerInterface to profile query count, SQL text, and cache effects.
Partial hydration
Section titled “Partial hydration”Use PartialHydrator or ScalarHydrator when full entity hydration is unnecessary — reporting paths, aggregate output, and read-only projections all benefit. See Hydration & Proxies.
Batch iteration
Section titled “Batch iteration”Avoid loading very large datasets with a single getResult() call. Process rows in bounded batches and call $entityManager->clear() between batches when the identity map would otherwise grow too large.
$batch = $entityManager ->createQueryBuilder(OrderSnapshot::class) ->orderBy('placed_at', 'ASC') ->limit($chunkSize) ->offset($offset) ->getResult();
$entityManager->clear();