Php 我可以强制ORM分解一个复杂的查询吗?

Php 我可以强制ORM分解一个复杂的查询吗?,php,cakephp,doctrine,Php,Cakephp,Doctrine,我正在用包含大量连接的条令进行查询。有些人只有一段感情,有些人有很多 我认为CakePHP会对每个关系进行单独的查询,但Doctrine似乎会进行一个巨大的查询。这两种方法都可以将数据水合物化,并将一个漂亮的数组返回到php脚本中,但它们似乎会生成不同的查询集。在Doctrine中,只要查询包含多个hasMany连接,性能就会变得非常糟糕 使用CakePHP时,默认情况是拆分查询,但我可以强制它加入(http://book.cakephp.org/view/872/Joining-tables)

我正在用包含大量连接的条令进行查询。有些人只有一段感情,有些人有很多

我认为CakePHP会对每个关系进行单独的查询,但Doctrine似乎会进行一个巨大的查询。这两种方法都可以将数据水合物化,并将一个漂亮的数组返回到php脚本中,但它们似乎会生成不同的查询集。在Doctrine中,只要查询包含多个hasMany连接,性能就会变得非常糟糕


使用CakePHP时,默认情况是拆分查询,但我可以强制它加入(http://book.cakephp.org/view/872/Joining-tables). 有没有一种方法可以在理论上做相反的事情:强制它将hasMany连接拆分为不同的查询?我尝试了文档和API,但还没有找到任何结果。

错误的解决方案:如果查询正确,一次使用多个联接进行查询应该比在多个SQL语句中使用分段查询更快

如果在添加n:n或1:n联接时,您的查询速度非常慢,那么在理论上,这有几个原因

在使用多个联接的查询中,最常见的错误之一是使用左联接+WHERE构造,其中可以使用带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条记录,那么这是一个非常慢的查询。它将首先将整个表b与表a连接起来,产生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%'
在这里,内部连接a.b不会以100000行结束,但是因为它使用了一个扩展的ON子句(理论称之为with),所以它只会留下一个小集合。因此,与其他语句中的性能相比,其他两个连接的速度将非常快

此外,请确保始终具有索引

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

如果您想知道数据库在幕后做什么,您可以在MySQL中键入
EXPLAIN
,然后查询,它会确切地告诉您为什么需要这么长时间。

原则允许您连接多个表,遍历多个一对一关系。这将导致查询的记录数呈指数增长(取决于连接的表的数量)。 水合过程将细化结果集,并从二维结果集(表)生成一棵树。 这对于较小的结果集和很少的表连接是合理的


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

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


按照@Elvis的解决方案,我将水合时间降至0.3秒。我所做的只是将查询拆分为两个单独的查询,第一个查询有60条记录,另一个查询有30条记录。

如果将其作为一个对象,会发生什么?难道条令的延迟加载不应该发挥作用吗?您的问题不是您正在查询的表上的不良索引吗?如果我是你,我会先在查询中运行descripe,看看是否有索引被使用。@dogmatic69,我想你是说EXPLAIN而不是descripe?谢谢,我使用的是LEFT JOIN+,这肯定会有帮助。不过,糟糕的表现还有第二个方面,我以前没有解释过。当数据从一个包含大量连接的查询返回时,数据中存在大量重复。(即,许多行几乎相同)。PHP脚本——本例中的原则——正在使用大量内存来补充所有这些重复数据;我希望分割查询,以减少重复并减少内存量。关于这一点,请注意几点。据我所知,与MySQL实际执行查询相比,所花费的时间应该可以忽略。你有介绍你的申请吗?信条的水合作用是一个过程,不应该比以任何其他方式处理一个大的结果集花费更长的时间。你使用什么水化模式?(尝试使用Hydrou数组,它比doctrine对象快得多。)您还可以使用它附带的ORM功能(即查找一个项目,然后导航到它的相关项,如
$creditcards=doctrine::getTable('Article')->findOneById($id)->Buyer->Creditcard