Symfony2中的Doctrine2:如何查看导致查询的对象调用? [英] Doctrine2 in Symfony2: How can I see which object-call leads into a query?

查看:157
本文介绍了Symfony2中的Doctrine2:如何查看导致查询的对象调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将Symfony2与Doctrine2一起使用.对于我的项目,我制作了具有不同关联映射的实体.首先,我确实看到了大约7个查询请求一个对象,因此我决定进行紧急加载",并将其减少为三个查询.

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.

但是在彼此直接调用的symfony工具栏(探查器)中,其中两个看起来是相同的.据我了解,我的代码中无需进行第三次查询.

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.

那么,我必须在哪里编写php文件中的断点,以查看我的代码的哪一行使该原理调用新查询?还是有另一种解决方案来查看我如何优化此请求?

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?

考虑了Artworkad的答案后,我必须详细介绍更多.这是因为我没有通过控制器发出2个对象请求.但这也许与我的树枝有关?

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 %}

对象关联

存在具有属性的关联Gebiet n:n Sektor.因此,我使用标准的[doctrine2关联映射( http: //docs.doctrine-project.org/en/latest/reference/association-mapping.html )ManyToOneOneToMany

Object association

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使用 Identity Map 模式来跟踪对象.因此,每当您从数据库中获取对象时,Doctrine都会在其UnitOfWork中保留对该对象的引用.基本上,它使用ID作为密钥来管理其UnitOfWork内部的对象.

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.

例如

$objectA = $this->entityManager->find('EntityName', 1);
$objectB = $this->entityManager->find('EntityName', 1);

将仅对数据库触发一个SELECT查询.在第二次呼叫中,该理论将检查身份映射,并在不进行数据库往返的情况下找到相同的ID.即使您使用代理对象,该对象也将具有相同的ID.

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.

但是

$objectA = $repository->findOneBy(array('name' => 'Benjamin'));
$objectB = $repository->findOneBy(array('name' => 'Benjamin'));

尽管您引用了相同的对象,但您仍会在SQL日志中看到两个查询. Doctrine仅通过ID识别对象,因此,即使是之前执行过的查询,也必须对数据库进行其他条件的查询.

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.

但是这种学说很聪明,它不会创建新实体,而是获取ID并查看其在内存中是否存在欺诈行为.

But doctrine is smart, it does not create a new entity but gets the ID and looks if it is alrady in memory.

PHP遵循写时复制范例,这是一种优化原则.仅当修改变量时,才创建变量的真实副本.因此,从数据库读取对象的请求的内存使用与不保留变量副本相同.

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.

因此,当您调用 flush 时,该学说将遍历Identiy Map,并将每个对象的原始属性与当前值进行比较.如果检测到更改,它将排队等待UPDATE查询.数据库中仅更改实际更新的字段.

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.

如何优化

因此有时将对象标记为只读(仅插入和删除)是有意义的,因此它们将不在更改集中(您可以在xml映射文件中或使用批注或在php代码中进行操作).

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)

或仅刷新一个实体

$entityManager->flush($entity)

这篇关于Symfony2中的Doctrine2:如何查看导致查询的对象调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆