Doctrine:left Join on table生成不必要的查询

时间:2010-11-18 17:17:53

标签: symfony1 doctrine left-join

我的环境的简短描述:

  • Symfony:1.4.8
  • 学说:1.2.3
  • Centos 5.5(PHP 5.3.3)
  • MySQL 5.1.52

我在Symfony中构建了一个新项目,这是项目架构:

# Car
RjCar:
  actAs: { Timestampable: ~ }
  columns:
    id: { type: integer(4), unsigned: true, primary: true, autoincrement: true }
    year: { type: integer(2), unsigned: true, notnull: true }
    engine_mod: { type: string(1000) }
    exterior_mod: { type: string(1000) }
    suspension_mod: { type: string(1000) }
    audio_mod: { type: string(1000) }
    vote_pos: { type: integer(4), notnull: true, unsigned: true, default: 0 }
    vote_neg: { type: integer(4), notnull: true, unsigned: true, default: 0 }
    views: { type: integer(4), notnull: true, unsigned: true, default: 0 }
    # Foreign keys
    category_id: { type: integer(1), unsigned: true, notnull: true }
    category_check: { type: boolean, notnull: true, default: 0 }
    user_id: { type: integer(5) }
  relations:
    RjCategory: { onDelete: CASCADE, local: category_id, foreign: id, foreignAlias: RjCars }
    sfGuardUser: { onDelete: CASCADE, local: user_id, foreign: id, foreignAlias: RjCars }

# Category
RjCategory:
  columns:
    id: { type: integer(1), unsigned: true, primary: true, autoincrement: true }
    name: { type: string(255), notnull: true}

# I do not include the sfGuardUser schema, but it's the default one from the plugin

当我想检索具有类别名称和用户名的最后10辆车时,我在RjCarTable.class.php中使用以下代码:

  $last_cars = $this->createQuery('car')
               ->leftJoin('car.sfGuardUser user')
               ->leftJoin('car.RjCategory categ')
               ->orderBy('car.created_at DESC')
               ->limit(10)
               ->execute();

   return $last_cars;

在我的页面上,一切都很好,我的所有结果都是如此,但在调试栏中,我看到了22个查询(而不是2个查询)。

以下是第一个正常的查询输出:

SELECT
/* Everything about the car */
r.id AS r__id, 
r.year AS r__year, 
r.engine_mod AS r__engine_mod, 
r.exterior_mod AS r__exterior_mod, 
r.suspension_mod AS r__suspension_mod, 
r.audio_mod AS r__audio_mod,  
r.vote_pos AS r__vote_pos, 
r.vote_neg AS r__vote_neg, 
r.views AS r__views, 
r.type_id AS r__type_id, 
r.category_id AS r__category_id, 
r.category_check AS r__category_check, 
r.user_id AS r__user_id, 
r.created_at AS r__created_at, 
r.updated_at AS r__updated_at, 
/* ... hidden because irrelevant... retrieve everything about the sfGuardUser and profile... */
/* Everything about the category */
r2.id AS r2__id, 
r2.name AS r2__name, 
FROM rj_car r 
LEFT JOIN sf_guard_user s ON r.user_id = s.id 
LEFT JOIN rj_category r2 ON r.category_id = r2.id 
ORDER BY r.created_at DESC 
LIMIT 10

因此,在此之前一切正常,除了此查询后面还有其他20个查询有关每个类别的信息(显然每个结果有2个查询),而您可以在上一个查询中注意到这些信息可用。我不会把所有这些都放在一边,但这里有一些:

SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '8') LIMIT 1
SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '8') LIMIT 1
SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '9') LIMIT 1
SELECT r.id AS r__id, r.name AS r__name FROM rj_category r WHERE (r.id = '9') LIMIT 1
/* etc.. 20 times */

所以我真正的问题是: - 为什么在第一个查询应该包含这些信息的同时执行所有这些不必要的查询? - 为什么sfGuardUser表没有发生这种情况?我的RjCar对象和sfGuardUser对象之间的关系显然与RjCar和RjCategory之间的关系相同。

如果有人已经面临同样的问题,我会很高兴听到这个问题。正如我所说的一切正常,但我更喜欢这个模块不会生成不必要的查询,因为它应该在我的应用程序的主页上执行。

3 个答案:

答案 0 :(得分:0)

这种行为似乎很奇怪,绝对不是预期的。有些事要尝试:

  • 你在缓存Doctrine查询或结果吗?有时,查询可以在更改模型后保持缓存,但效果很奇怪。
  • 这些查询肯定看起来像是Doctrine的懒惰行为。您是否尝试缩小哪些调用专门触发这些查询?尝试跟踪哪些特定行触发查询,并查看它们是否有任何特殊之处。

答案 1 :(得分:0)

我打了自己:

这是我在RjCar.class.php

中找到的内容
/**
* Return the category of the car
*/    
public function getRjCategory(){
  return Doctrine_Core::getTable('RjCategory')->find($this->getCategoryId());
}

所以它解释了不必要的查询...我甚至不记得编写这段代码,但考虑到我是唯一一个从事该项目的人,我想这就是我。

像往常一样,问题出在椅子和键盘之间......

感谢您的帮助。

答案 2 :(得分:-1)

当使用像Doctrine和Hibernate这样的ORM框架时,它经常会产生冗余和丑陋的查询。查询越复杂,它在这些系统上就越丑陋(尝试在连接的查询中添加“限制”并查看生成的代码)。
框架通常为80%的案例提供了很好的解决方案。对于剩下的20%,你需要稍微努力一点。通常这是一个公平的权衡 如果您担心此查询的输出质量,或者认为您无法承受它导致的延迟 - Doctrine有一种非常简单的方法来编写和管理自定义查询。不要害怕走那条路......