douyue1998 2013-03-01 08:06
浏览 59
已采纳

Symfony2中的Doctrine2:如何查看哪个对象调用导致查询?

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?

Update:

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?

My Controller

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));
    }

My Twig Template

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

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

My 3 listed queries from profiler

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]
  • 写回答

1条回答 默认 最新

  • doulu3399 2013-03-01 09:17
    关注

    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)
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 求用stm32f103c6t6在lcd1206上显示Door is open和password:
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类