我可以强制Doctrine ORM拆分复杂的查询吗?

时间:2010-11-19 18:11:48

标签: php cakephp doctrine

我正在使用包含大量连接的Doctrine进行查询。有些是hasOne关系,有些是hasMany。

我认为CakePHP对每个hasMany关系进行单独的查询,但是Doctrine似乎做出了一个巨大的查询。两者都可以保存数据并将一个很好的数组返回到您的PHP脚本中,但它们似乎会使不同的查询集合这样做。使用Doctrine,只要您的查询包含多个hasMany连接,性能就会变得非常糟糕。

使用CakePHP,默认是拆分查询,但我可以强制它加入(http://book.cakephp.org/view/872/Joining-tables)。有没有办法在Doctrine中执行相反的操作:强制它将hasMany连接拆分为不同的查询?我已经尝试过文档和API,但还没有找到任何内容。

3 个答案:

答案 0 :(得分:2)

错误的解决方案:一旦查询正确,一次查询多个连接应始终比在多个SQL语句中使用碎片查询更快。

如果你的查询在添加n:n或1:n连接时非常缓慢,那么在Doctrine中,有几个原因。

使用多个连接的查询中最常出现的错误之一是使用LEFT JOIN + WHERE结构,您可以在其中使用INNER JOIN和ON。考虑一下这个DQL示例:

SELECT a.*, c.*
  FROM Article a
  LEFT JOIN a.Buyer b
  LEFT JOIN b.Creditcard c
  LEFT JOIN c.digitalinfo d
  WHERE b.id = 2 AND d.info LIKE 'TEST%'

如果所有表都有10000条记录,那么这是一个非常慢的查询。它将首先用表a连接整个表b,产生10000 ^ 2行,而在你的WHERE子句中,你扔掉了99.9%的所有行。

SELECT a.*, c.*
  FROM Article a
  INNER JOIN a.Buyer b WITH b.id=2
  LEFT JOIN b.Creditcard c
  INNER JOIN c.Digitalinfo d WITH d.info LIKE 'TEST%'

在这里,INNER JOIN a.Buyer b最终没有100 000 000行,但由于它使用了一个扩展的ON子句(Doctrine将此WITH调用),它只会留下一小部分。因此,与其他声明中的表现相比,其他两个连接将快速闪电。

另外,请确保您始终拥有指数

  • 在您搜索的列上。 (如果您搜索全名,如在FirstName +''+ LastName中,请在该序列上创建索引!)
  • 上执行特定连接的列上
  • 在外键和字段上,它们的引用设置为。

如果你想知道你的数据库在幕后做了什么,你可以在MySQL类型EXPLAIN后跟你的查询,它会告诉你为什么这么长时间。

答案 1 :(得分:0)

Doctrine允许您加入多个表,遍历多个oneToMany关系。这导致查询具有指数(在已连接的表的数量上)记录的数量。 水化过程比精炼结果集并从您的二维结果集(表)中生成树。 这对于小的结果集来说是合理的,很少有表加入。

如果您有相关数量的表和记录,则必须单独进行查询。

答案 2 :(得分:0)

我也遇到了这个问题。我有一个查询花了0.0060秒执行它的原始形式,但阵列水合过程需要8秒。由于多个左连接,查询返回2180行(这是一个单独的实体,具有所有关系)。

按照@Elvis的解决方案,我将保湿时间减少到0.3秒。我所做的只是将查询分成两个单独的查询,最后是第一个有60条记录,另外30条记录。