【问题标题】:Doctrine nest multiple joins教义嵌套多个连接
【发布时间】:2011-03-26 21:17:21
【问题描述】:

我正在尝试使用 Doctrine 优化 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 和 Doctrine 的文档,但找不到我的答案。我也在谷歌上搜索了一段时间。 (几个月来我一直在寻找解决方案)我希望我已经足够好地描述了我的问题。

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

【问题讨论】:

    标签: join symfony1 doctrine


    【解决方案1】:

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

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

    $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 是一个包含选定数据的数组。拥有所有数据后,您可以根据需要创建一个数组,但请记住,这样您只执行一次查询(减少数据库负载),但会添加一些时间机器来解析数组。

    【讨论】:

    • 我设法通过重写代码将加载时间减少了 100-150 毫秒:pastebin.com/rS2v2nSF 这是最好的方法还是有更好的方法?
    • 我阅读了代码。我们在谈论多少个项目?因为通过这种方式,您将数据库负载转移到解析负载,并且您可能没有使用所有项目(如果是,请过滤它们)。有时最好有更多的查询和更少的解析,但总是取决于有多少数据。例如,您可以执行 2 个查询:一个带来项目数据(if 块),另一个带来进度和原始数据。优化查询的方法是减少连接表。检查pastebin.com/svXux2pv
    • 我看过你的代码。我们正在谈论 1 到 20 个开放项目,我需要所有项目,因为此页面是一个列表,显示每个开放项目的进度。 (忘记添加 where 条件以过滤掉已完成的条件)当前页面的加载时间现在是 450 毫秒。我会尝试使用您的代码,sql 有一些东西需要修复。我将比较两者之间的加载时间。
    • 两个函数都需要大约 38 毫秒才能完成,这比以前快得多。谢谢!您知道如何加快查看速度吗?剩下的唯一一件事就是减慢一切。 (无法缓存,因为数据是动态的)
    • Nice :) 我认为加快浏览速度的唯一方法是减少 foreach 的 *、*if 等,使其尽可能简单。仅加载将要使用的 js 并减小图像大小。有很多加速网站的最佳实践,只需使用 google :) 例如检查 bit.ly/hgOcOm
    【解决方案2】:

    您需要修改获取Project 对象的查询以包含连接。按照惯例,获取Project 对象的查询应该放在ProjectTable 中。

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

    【讨论】:

    • 如果我修改查询,查询量从17增加到253。进度子集总是空的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多