2

我有一个相同类的 Active Record 对象数组。该对象具有定义的关系。初始化“父”对象后,有没有办法以“批量”方式读取相关对象?

示例我定义了 AR 类PostUserComment * Post * 有关系所有者(BELONGS_TO) 到类User和关系评论(HAS_MANY) 到类Comments

我有一个$posts类对象的数组Post。由于不同的原因,$posts不能从一开始就初始化

'with' => array('owner', 'comments')

如果我这样做:

foreach ($posts as $post) {
   var_dump($post->owner);
   var_dump($post->comments);
}

对于每一个$post ,都应该为 retriving owner和 retriving comments进行查询。这可能导致大量查询和脚本执行缓慢。更好的方法是一步读取一种类型的所有相关对象。

是否存在这样的东西来检索对象数组的某个关系的所有相关对象?:

Post::readRelatedObject($posts, 'owner'); 
Post::readRelatedObject($posts, 'comments');

我需要这种方法有几个原因:

  1. 有时我无法提前知道是否需要初始化关系。
  2. 在“父母”之后读取相关对象可能会快得多,因为连接可能很慢。
  3. 缓存可能会受到影响,因为有时“父”对象不能与相关对象具有相同的缓存时间,因此在从缓存中提取父对象之后以分组/批量方式读取相关对象可能很有用。例如:$post已缓存,但我无法将最后 3 条评论与帖子一起缓存。

yii 是否包含这样的内容?或者可以提供帮助的插件?

谢谢

4

3 回答 3

2

如果您正在尝试针对这样的大型结果集进行优化,您几乎总是最好自己滚动。Yii 开发人员甚至建议不要在这样的复杂情况下使用 activerecord(加载顺序非常不同)。

虽然

首先,我建议根据您检索到的所有帖子的 ID 构建自己CDBCriteria的。如果您在Posts模型中执行此操作,它也与为关系定义的标准很好地绑定(显然不完美)。

static public function loadComments(array $ids)
{
    $crit = Comment::model()->dbCriteria;
    $crit->addInCondition('post_id', .....

    .....
    return Comment::model()->findAll($crit);
}

这将为您返回该组 ID 的所有评论,您甚至可以进行一些额外的处理以通过它们所属的帖子 ID 来索引它们。

但是,真的

在您的评论中,您说这 100 条帖子每条有 200 条评论可能意味着加载 2000 条(实际上是 20 000 条)。但是,如果您在一个页面上加载了这么多帖子 + 评论,那么您的优化就错了。

在我看来,在担心数据库查询大小之前,您有一些事情需要实现:

  1. 在需要之前不要加载评论,无论是单击按钮,滚动到该帖子的标题,还是只是逐步向下页面直到完成。这样,服务器一次只查找一个帖子的评论,用户甚至可能不想看到第 99 号帖子的评论。

  2. 不要每页加载 100 个帖子,除非它们是非常小的帖子(在这种情况下,有什么好担心的)。再次渐进式滚动将有所帮助,甚至分页

  3. 过滤你的结果,只显示那些相关的,用户想看的帖子很可能没有 100 条,如果有 200 条评论,有多少用户会阅读超过 10 条?

如果你实现其中之一,我认为结果集大小的问题就会消失。

然而

如果您确实需要担心 20 000 行,那么您应该首先关注 ActiveRecord 实例化。20 000 行在任何正常设置中都无需担心,但 20 000 活动记录对象肯定是,即使在更高规格的系统上也是如此。如果您正在处理非常大和/或复杂的数据集,您应该使用 DAO。

于 2013-02-28T15:27:36.590 回答
0

我不知道可以做到这一点的扩展。也许你可以创建一个 yii 应该知道关于数据的一切来解决这个任务。

假设comment有一个指向表中的post_id链接。idpost

有几个选项可以加载帖子的相关评论。

选项 1:使用 ID 查询所需的评论。一些 DBMS 限制了 SQL 查询的长度,因此您可能必须小心,不要在 IN 子句中放置许多 ID。也许这必须分成多个查询。

  1. 迭代给定$posts的并将 post 存储id在列表中。
  2. 运行 SQL 查询,例如SELECT * FROM comments WHERE post_id IN ([the IDs from the list]).
  3. 将结果合并到您的$posts.

选项 2:要修复可能的 IN 子句限制,请改用 JOIN。

  1. 运行 SQL 查询,如SELECT * FROM comments JOIN [the SELECT query for the posts].

选项 3(我的首选):根据您的用例,重新加载所有带有评论和作者的帖子(通过在模型中定义)可能是最with干净的criteriaposts

  1. 添加条件withif ($loadDetails) { criteria->'with' => array('owner', 'comments'); }
于 2013-02-24T11:32:20.617 回答
0

如果您主要关心的是避免延迟加载并希望检索所有 Post 及其相关的所有者和评论记录。

这可能对你有用。

$criteria = new CDbCriteria();
$criteria->with = array('comments','owner');
$result = $Post->together()->findAll($criteria);

参考: http ://www.yiiframework.com/doc/api/1.1/CActiveRecord#together-detail http://www.yiiframework.com/doc/api/1.1/CDbCriteria#with-detail

希望这能回答您的问题。

于 2013-02-27T04:02:18.313 回答