Doctrine използва Карта на самоличността модел за проследяване на обекти. Така че всеки път, когато извличате обект от базата данни, Doctrine запазва препратка към този обект в своята UnitOfWork. И по същество той използва идентификатора като ключ за управление на обекти в своята UnitOfWork.
Напр.
$objectA = $this->entityManager->find('EntityName', 1);
$objectB = $this->entityManager->find('EntityName', 1);
ще задейства само една заявка SELECT към базата данни. Във второто повикване доктрината ще провери картата на идентичността и ще намери същия идентификатор, без да прави двупосочно пътуване с база данни. Дори ако използвате прокси обект, обектът ще има същия идентификатор.
Но за
$objectA = $repository->findOneBy(array('name' => 'Benjamin'));
$objectB = $repository->findOneBy(array('name' => 'Benjamin'));
ще видите две заявки във вашия SQL дневник, въпреки факта, че препращате към един и същ обект. Doctrine познава обекти само по ID , така че заявка за различен критерий трябва да отиде в базата данни, дори ако е била изпълнена преди това.
Но доктрината е умна, тя не създава нов обект, а получава идентификатора и гледа дали вече е в паметта.
PHP следва парадигмата на копиране при запис, това е принцип на оптимизация. Истинско копие на променлива се прави само когато променливата е променена. Така че използването на паметта за заявка, която чете обекти от базата данни, е същата, както ако не се запази копие на променлива.
Така че само когато промените променливи, вашите приложения създават вътрешно нови променливи и консумират памет.
Така че, когато извикате flush , доктрината преглежда Identiy Map и сравнява оригиналното свойство на всеки obecjts с текущите стойности. Ако бъдат открити промени, той ще се постави на опашка за заявка UPDATE. Само действително актуализираните полета се променят в базата данни.
Как да оптимизираме
Така че понякога има смисъл да маркирате обекти като само за четене (само вмъкване и премахване), така че те да не са в набора от промени (можете да го направите във вашия xml файл за съпоставяне или с пояснения или във вашия php код).
$entityManager->getUnitOfWork()->markReadOnly($entity)
Или изчистете само един обект
$entityManager->flush($entity)