使用 eloquent 从大型数据集中查询计数
Querying counts from large datasets using eloquent
我有以下关系:
一个工作有很多角色。
public function roles()
{
return $this->hasMany(Role::class);
}
一个角色有很多轮班和轮班分配。
public function shifts()
{
return $this->hasMany(Shift::class);
}
public function assignments()
{
return $this->hasManyThrough(Assignment::class, Shift::class);
}
一个班次有很多作业。
public function assignments()
{
return $this->hasMany(Assignment::class);
}
我需要统计具有特定状态的所有作业,比方说 "Approved"。这些计数导致我的应用程序运行极其缓慢。以下是我一直以来的做法:
foreach ($job->roles as $role){
foreach ($role->shifts as $shift) {
$pendingCount = $shift->assignments()->whereStatus("Pending")->count();
$bookedCount = $shift->assignments()->whereIn('status', ["Booked"])->count();
}
}
我确信一定有更好、更快的方法。其中一些查询需要超过 30 秒以上的时间。有成千上万的作业,我知道这会影响性能。我怎样才能加快这些查询的速度?
您 运行 进入 N+1 问题几次。你想通过作业延迟加载嵌套分配然后你可以访问关系并且你的 where()
和 whereIn()
调用在返回的集合而不是查询构建器上执行,这就是为什么你必须使用 where('status', "Pending")
而不是我示例中的 whereStatus("Pending")
因为集合不会自动解决此约束:
$job = Job::with('roles.assignments')->find($jobId);
foreach ($job->roles as $role) {
$pendingCount = $role->assignments->where('status', "Pending")->count();
$bookedCount = $role->assignments->whereIn('status', ["Booked"])->count();
}
这对你来说应该快得多。
更新
您甚至可以更进一步,映射结果并将结果存储在角色的 属性 中:
$job->roles->map(function($role) {
$role->pending_count = $role->assignemnts->where('status', "Pending")->count();
$role->booked_count = $role->assignments->whereIn('status', ["Booked"])->count();
return $role;
});
我有以下关系:
一个工作有很多角色。
public function roles()
{
return $this->hasMany(Role::class);
}
一个角色有很多轮班和轮班分配。
public function shifts()
{
return $this->hasMany(Shift::class);
}
public function assignments()
{
return $this->hasManyThrough(Assignment::class, Shift::class);
}
一个班次有很多作业。
public function assignments()
{
return $this->hasMany(Assignment::class);
}
我需要统计具有特定状态的所有作业,比方说 "Approved"。这些计数导致我的应用程序运行极其缓慢。以下是我一直以来的做法:
foreach ($job->roles as $role){
foreach ($role->shifts as $shift) {
$pendingCount = $shift->assignments()->whereStatus("Pending")->count();
$bookedCount = $shift->assignments()->whereIn('status', ["Booked"])->count();
}
}
我确信一定有更好、更快的方法。其中一些查询需要超过 30 秒以上的时间。有成千上万的作业,我知道这会影响性能。我怎样才能加快这些查询的速度?
您 运行 进入 N+1 问题几次。你想通过作业延迟加载嵌套分配然后你可以访问关系并且你的 where()
和 whereIn()
调用在返回的集合而不是查询构建器上执行,这就是为什么你必须使用 where('status', "Pending")
而不是我示例中的 whereStatus("Pending")
因为集合不会自动解决此约束:
$job = Job::with('roles.assignments')->find($jobId);
foreach ($job->roles as $role) {
$pendingCount = $role->assignments->where('status', "Pending")->count();
$bookedCount = $role->assignments->whereIn('status', ["Booked"])->count();
}
这对你来说应该快得多。
更新
您甚至可以更进一步,映射结果并将结果存储在角色的 属性 中:
$job->roles->map(function($role) {
$role->pending_count = $role->assignemnts->where('status', "Pending")->count();
$role->booked_count = $role->assignments->whereIn('status', ["Booked"])->count();
return $role;
});