我正在使用包含大量连接的Doctrine进行查询。有些是hasOne关系,有些是hasMany。
我认为CakePHP对每个hasMany关系进行单独的查询,但是Doctrine似乎做出了一个巨大的查询。两者都可以保存数据并将一个很好的数组返回到您的PHP脚本中,但它们似乎会使不同的查询集合这样做。使用Doctrine,只要您的查询包含多个hasMany连接,性能就会变得非常糟糕。
使用CakePHP,默认是拆分查询,但我可以强制它加入(http://book.cakephp.org/view/872/Joining-tables)。有没有办法在Doctrine中执行相反的操作:强制它将hasMany连接拆分为不同的查询?我已经尝试过文档和API,但还没有找到任何内容。
答案 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调用),它只会留下一小部分。因此,与其他声明中的表现相比,其他两个连接将快速闪电。
另外,请确保您始终拥有指数
如果你想知道你的数据库在幕后做了什么,你可以在MySQL类型EXPLAIN
后跟你的查询,它会告诉你为什么这么长时间。
答案 1 :(得分:0)
Doctrine允许您加入多个表,遍历多个oneToMany关系。这导致查询具有指数(在已连接的表的数量上)记录的数量。 水化过程比精炼结果集并从您的二维结果集(表)中生成树。 这对于小的结果集来说是合理的,很少有表加入。
如果您有相关数量的表和记录,则必须单独进行查询。
答案 2 :(得分:0)
我也遇到了这个问题。我有一个查询花了0.0060秒执行它的原始形式,但阵列水合过程需要8秒。由于多个左连接,查询返回2180行(这是一个单独的实体,具有所有关系)。
按照@Elvis的解决方案,我将保湿时间减少到0.3秒。我所做的只是将查询分成两个单独的查询,最后是第一个有60条记录,另外30条记录。