我有一个同一类的 Active Record 对象数组。 该对象具有已定义的关系。 有没有办法在“父”对象初始化后以“批量”方式读取相关对象?
示例 我定义了 AR 类 Post、User、Comment *帖子*与用户类有所有者 (BELONGS_TO) 关系,与评论 (HAS_MANY) 类<强>评论
我有一个 $posts 类 Post 对象的数组。 由于不同的原因,$posts 无法从一开始就用
进行初始化'with' => array('owner', 'comments')
如果我这样做:
foreach ($posts as $post) {
var_dump($post->owner);
var_dump($post->comments);
}
对于每个$post,都应该进行检索所有者的查询和检索评论的查询。 这可能会导致大量查询和脚本执行缓慢。 更好的方法是一步读取一种类型的所有相关对象。
是否存在这样的方法来检索对象数组的特定关系的所有相关对象?:
Post::readRelatedObject($posts, 'owner');
Post::readRelatedObject($posts, 'comments');
我需要这种方法有几个原因:
- 有时我无法提前判断是否需要初始化关系。
- 读取“父对象”之后的相关对象可能会快得多,因为连接可能会很慢。
- 缓存可能会受到影响,因为有时“父”对象无法与相关对象具有相同的缓存时间,因此从缓存中提取父对象后,以分组/批量方式读取相关对象可能会很有用。例如:$post 已缓存,但我无法将最后 3 条评论与帖子一起缓存。
yii 包含这样的东西吗?或者一个可以提供帮助的插件?
谢谢
最佳答案
如果您尝试针对这样的大型结果集进行优化,那么您最好自行推出。 Yii 开发者 even recommend对于这样的复杂情况不使用 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 个)。但是,如果您在单个页面上加载那么多帖子和评论,那么您就在错误的位置进行了优化。
在我看来,在担心数据库查询大小之前,您需要实现一些事情:
在需要之前不要加载评论,无论是单击按钮、滚动到帖子标题还是简单地逐步向下滚动页面直至完成。这样服务器一次只查找一个帖子的评论,用户甚至可能不想看到第 99 号帖子的评论。
不要每页加载 100 个帖子,除非它们是非常小的帖子(在这种情况下,有什么可担心的)。再次渐进滚动将会有所帮助,甚至 pagination
过滤结果以仅显示相关的内容,用户希望看到的帖子很可能不是 100 条,如果有 200 条评论,有多少用户会阅读超过 10 条?
如果您实现其中之一,我认为结果集大小的问题就会消失。
但是
如果您确实需要担心 20 000 行,那么 ActiveRecord 实例化应该首先出现在您的雷达上。在任何正常设置中,20 000 行都无需担心,但 20 000 个事件记录对象当然是值得担心的,即使在更高规范的系统上也是如此。如果您正在处理非常大和/或复杂的数据集,您应该使用 DAO。
关于php - 父对象初始化后初始化相关对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15010031/