I'm using Symfony2 with Doctrine2. For my project I made Entities with different association-mapping. First I did see about 7 queries for requesting one object, so i decided to make "eager-loading" and it reduced to three queryies.
But two of them looks to be the same in the symfony toolbar (Profiler) directly called after each other. In my understanding there is no need of a third query in my code.
So where do I have to set my breakpoints in the doctrine php files to see which line of my code makes doctrine calling a new query? Or is there another solution to see how i can optimize this requests?
After thinking about Artworkad answer, I have to go much more in detail. This is because I do not make 2 object request via my Controller. But perhaps it has something to do with my twig?
public function gebietAction($gebiet){
$em = $this->getDoctrine()->getEntityManager();
/* @var $gebietobj Gebiet */
$gebietobj = $em->getRepository('ACGSigwxBundle:Gebiet')->findOneBy(array('short' => $gebiet));
if (!$gebietobj) {
throw $this->createNotFoundException('Kann das angegebene Gebiet nicht finden!');
}
return $this->render('ACGSigwxBundle:Sigwx:sigwx.html.twig',array("gebiet"=>$gebietobj));
}
{% extends "ACGSigwxBundle::layout.html.twig" %}
{% block content %}
<h1>{{ gebiet.getName() }}</h1>
<p>My sectors:</p>
<ul>
{% for gs in gebiet.getGebietssektoren() %}
<li>{{ gs.getSektor().getName() }}</li>
{% endfor %}
</ul>
{% endblock %}
There is a association Gebiet n:n Sektor
with attributes. So i made Gebiet 1:n Gebietsektoren n:1 Sektor
with standard [doctrine2 association mappings(http://docs.doctrine-project.org/en/latest/reference/association-mapping.html) ManyToOne
and OneToMany
SELECT t0.id AS id1, t0.name AS name2, t0.short AS short3, t0.parent_id AS parent_id4 FROM gebiet t0 WHERE t0.short = ? LIMIT 1 Parameters: [app]
SELECT t0.id AS id1, t0.position AS position2, t0.size AS size3, t0.gebiet_id AS gebiet_id4, t0.sektor_id AS sektor_id5, t6.id AS id7, t6.name AS name8, t6.typ AS typ9, t6.erweitert AS erweitert10, t6.sortorder AS sortorder11 FROM gebietssektoren t0 INNER JOIN sektor t6 ON t0.sektor_id = t6.id WHERE t0.gebiet_id = ? Parameters: [1]
SELECT t0.id AS id1, t0.position AS position2, t0.size AS size3, t0.gebiet_id AS gebiet_id4, t0.sektor_id AS sektor_id5, t6.id AS id7, t6.name AS name8, t6.typ AS typ9, t6.erweitert AS erweitert10, t6.sortorder AS sortorder11 FROM gebietssektoren t0 INNER JOIN sektor t6 ON t0.sektor_id = t6.id WHERE t0.gebiet_id = ? Parameters: [1]
Doctrine uses the Identity Map pattern to track objects. So whenever you fetch an object from the database, Doctrine keeps a reference to this object inside its UnitOfWork. And basically it uses the ID as a key to manage objects inside its UnitOfWork.
E.g.
$objectA = $this->entityManager->find('EntityName', 1);
$objectB = $this->entityManager->find('EntityName', 1);
would fire only one SELECT query against the database. In the second call doctrine will check the identity map and would find the same ID without doing a database roundtrip. Even if you use proxy object, the object would have same ID.
But for
$objectA = $repository->findOneBy(array('name' => 'Benjamin'));
$objectB = $repository->findOneBy(array('name' => 'Benjamin'));
you would see two queries in your SQL log, despite the fact that you reference the same object. Doctrine only knows objects by ID, so a query for a different criteria has to go to the database, even if it was executed before.
But doctrine is smart, it does not create a new entity but gets the ID and looks if it is alrady in memory.
PHP follows the copy-on-write paradigm, it's a optimization principle. A real copy of a variable is only made when the variable is modified. So the memory usage for a request that reads objects from database is the same as if not to keep a variable copy.
So only when you change variables your applications creats new variables internally and consumes memory.
So when you call flush , doctrine iterates over the Identiy Map and compares each obecjts's original property with the current values. If changes are detected it will queue for an UPDATE query. Only actually updated fields are changed in database.
How to optimize
So sometimes it makes sense to mark objects as read only (only insert and remove), so they will not be in the changeset (you can do it in your xml mapping file or with annotations or in your php code).
$entityManager->getUnitOfWork()->markReadOnly($entity)
Or flush only one entity
$entityManager->flush($entity)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With