Doctrine používá Mapu identity vzor pro sledování objektů. Takže kdykoli načtete objekt z databáze, Doctrine uchová odkaz na tento objekt ve své UnitOfWork. A v podstatě používá ID jako klíč ke správě objektů v UnitOfWork.
Např.
$objectA = $this->entityManager->find('EntityName', 1);
$objectB = $this->entityManager->find('EntityName', 1);
by vyvolal pouze jeden dotaz SELECT proti databázi. Ve druhém volání doktrína zkontroluje mapu identity a najde stejné ID, aniž by provedla zpáteční cestu databáze. I když použijete objekt proxy, objekt bude mít stejné ID.
Ale pro
$objectA = $repository->findOneBy(array('name' => 'Benjamin'));
$objectB = $repository->findOneBy(array('name' => 'Benjamin'));
v protokolu SQL byste viděli dva dotazy, a to navzdory skutečnosti, že odkazujete na stejný objekt. Doktrína zná objekty pouze podle ID , takže dotaz na jiná kritéria musí jít do databáze, i když byl dříve proveden.
Ale doktrína je chytrá, nevytváří novou entitu, ale získává ID a hledá, jestli už je v paměti.
PHP se řídí paradigmatem copy-on-write, je to princip optimalizace. Skutečná kopie proměnné se vytvoří pouze tehdy, když je proměnná upravena. Využití paměti pro požadavek, který čte objekty z databáze, je tedy stejné, jako kdyby se neuchovávala kopie proměnné.
Takže pouze když změníte proměnné, vaše aplikace vytvoří nové proměnné interně a spotřebovávají paměť.
Takže když zavoláte flush , doktrína iteruje přes Identiy Map a porovnává původní vlastnost každého obecjta s aktuálními hodnotami. Pokud jsou zjištěny změny, zařadí se do fronty na dotaz UPDATE. V databázi se mění pouze aktuálně aktualizovaná pole.
Jak optimalizovat
Někdy má tedy smysl označit objekty jako pouze pro čtení (pouze vložit a odebrat), takže nebudou v changesetu (můžete to udělat ve vašem xml mapovacím souboru nebo pomocí anotací nebo ve vašem php kódu).
$entityManager->getUnitOfWork()->markReadOnly($entity)
Nebo vyprázdněte pouze jednu entitu
$entityManager->flush($entity)