2011-03-26 84 views
0

我想优化symfony应用程序与教义。我偶然发现了以下问题:学说嵌套多个连接

在视图中我使用了$ project-> getProgress();但通过这样做,查询数量会随着项目数量的增加而增加。所以我试图用左连接将进度放到项目查询中(重写findAll方法),但是这并没有解决。查询的数量实际上增加了。

public function findAll($hydrationMode = null) 
{ 
    $q = $this->createQuery('p') 
        ->leftJoin('p.progress pr') 
        ->leftJoin('pr.sfGuardUser u') 
        ->leftJoin('p.raws r') 
        ->leftJoin('p.series'); 
    return $q->execute(array(), $hydrationMode); 
} 

这是我试图用尽可能少的查询创建结果:

array() { 
    [0]=> 
    array() { 
    ["id"]=> string(1) "1" 
    ... 
    ["progress"]=> 
    array() { 
     array() { 
      array() { progress1 } 
      array() { progress2 } 
      array() { progress3 } 
      .... 
     } 
    } 
    } 

我通过两个Symfony和学说的文件看,但没有找到我回答。我也在谷歌上搜索了很长一段时间。 (我几个月来一直在寻找解决方案)我希望我已经描述了我的问题。

的schema.yml:

projects: 
    actAs: 
    Timestampable: ~ 
    columns: 
    user_id: integer(4) 
    series_id: bigint 
    pages: int 
    chapter: string 
    translators_id: bigint 
    proofreaders_id: bigint 
    cleaners_id: bigint 
    typesetters_id: bigint 
    raws_id: bigint 
    hide_project: bool 
    complete: bool 
    relations: 
    sfGuardUser: 
     local: user_id 
     foreign: id 
     onDelete: CASCADE 
    series: 
     local: series_id 
     foreign: id 
     type: one 
     foreignType: many 
     onDelete: CASCADE 
    progress: 
     local: id 
     foreign: projects_id 
     onDelete: CASCADE 
     type: one 
     foreignType: many 

projectsProgress: 
    actAs: [Timestampable] 
    columns: 
    projects_id: bigint 
    user_id: integer(4) 
    job: 
     type: enum 
     notnull: true 
     values: [tl,pr,cl,ts] 
    beginpage: int 
    endpage: int 
    complete: bool 
    file: string 
    url: clob 
    relations: 
    sfGuardUser: 
     local: user_id 
     foreign: id 
     onDelete: CASCADE 
    projects: 
     local: projects_id 
     foreign: id 
     onDelete: CASCADE 
     foreignAlias: progress 

回答

0

使用水合物模式的问题是您可以获取不会使用的数据。我真的不知道如何获取所有数据,但假设每个项目都会添加所有必需的数据,至少还有一个查询...

对于复杂查询(和优化),我更喜欢做一个手动查询,设法将所有需要的数据在一个查询,例如:

$query = "SELECT ... FROM projects p LEFT JOIN progress pr (LEFT JOIN sfGuardUser u (LEFT JOIN...) ON pr.user_id = u.id) ON p.id = pr.projects_id" 

$rs = Doctrine_Manager::getInstance()->getCurrentConnection()->fetchAssoc($query); 

$ RS与选择的数据阵列。拥有所有的数据,你可以根据你的喜好制作一个数组,但要记住,这样你可以做一个查询(减少数据库负载),但是添加一些时间机器来解析数组。

+0

我设法通过重写这样的代码来减少100-150ms的加载时间:http://pastebin.com/rS2v2nSF 这是实现它的最好方法还是有更好的方法? – ikore 2011-03-27 16:27:48

+0

我正在阅读代码。我们在谈论多少个项目?因为这种方式可以将数据库负载转移到解析负载,并且您可能没有使用所有项目(如果是这样,请过滤它们)。有时最好多一些查询,少一些解析,但总是取决于多少数据。例如,您可以执行2个查询:一个带来项目数据(if块),另一个带来进度和原始数据。优化查询的方法是减少连接表。检查http://pastebin.com/svXux2pv – Pabloks 2011-03-27 19:51:52

+0

我见过你的代码。我们正在讨论1到20个开放项目,我需要所有项目,因为这个页面是一个列表,显示每个开放项目的进度。 (忘记添加where条件来过滤完成的)现在页面的加载时间现在是450ms。我会试着玩你的代码,有一些需要修复的sql。我会比较两者之间的加载时间。 – ikore 2011-03-27 20:36:24

0

您需要修改的获取对象Project包括联接的查询。通常情况下,应将提取Project对象的查询置于ProjectTable中。

如果要修改所有查询或Project查询的子集,请查看Doctrine Query Execution Listeners

+0

如果我修改查询,查询量从17增加到253,并且进度的子集总是空的。 – ikore 2011-03-27 14:42:30