我正在使用 Laravel 10 开发一个应用程序,并且面临与急切加载嵌套关系和自定义访问器相关的性能问题。
场景: 我有三个模型:用户、帖子和评论。
一个用户有很多帖子。 一个帖子有很多评论。 我在 Post 模型上设置了一个自定义访问器来计算评论数。
以下是我的模型的相关部分:
// User.php
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
}
// Post.php
class Post extends Model
{
protected $appends = ['comment_count'];
public function comments()
{
return $this->hasMany(Comment::class);
}
public function getCommentCountAttribute()
{
return $this->comments()->count();
}
}
// Comment.php
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}
问题: 在我的控制器中,我试图加载所有用户的帖子以及每个帖子的评论数量。我是这样做的:
$users = User::with(['posts.comments'])->get();
我面临的问题是,由于 N+1 查询问题,这种方法导致性能显着下降。为每个帖子调用自定义访问器 getCommentCountAttribute,这会导致为每个帖子的评论计数执行一个新查询。
我尝试过的:
$users = User::with(['posts' => function($query) {
$query->withCount('comments');
}])->get();
这可行,但问题是它不使用自定义访问器,因此未填充 Post 模型中的 comment_count 属性。
$users->loadMissing('posts.comments');
但这并不能解决性能问题,因为它仍然会导致过多的查询。
有没有一种方法可以继续使用自定义访问器,同时避免 N+1 查询问题?如何优化这种急切加载以减少查询数量,同时仍然有效地获取每个帖子的 comment_count ?任何见解或替代方法将不胜感激!
将访问器更改为:
public function getCommentCountAttribute()
{
return $this->comments->count();
}
这具有在模型上加载
comments
关系的效果(如果尚未加载)。由于您使用的是 User::with(['posts.comments']);
,因此帖子将已加载
comments
关系。
getCommentsCountAttribute
,以便可以用
comments_count
调用它(注意复数)。 Laravel 自动使用关系名称来设置 count 属性。关系是
comments
。