很长时间以来,我一直在寻找这个问题的解决方案:

假设我们有2个表,其中一个表是Clients表,第二个表是ClientAssignment表:
ClientAssignment表与Clients表相关:

public function assignment()
{
    return $this->hasOne(ClientAssignment::class, 'client_id');
}


现在,当我想计算有多少ClientAssignment的客户时,我这样做:

$users =[1,2,3,4 .....]
$userAssignments = array();

foreach ($users as $user) {

    $user_assignments = Client::whereHas('assignment', function ($query) use ($user) {
     $query->where('assigned_id', $user);
    });

     $ua['user_id'] = $user;
     $ua['count'] = $user_assignments->count();
     array_push($userAssignments, $ua);
   }


该代码运行良好,但在具有80k个客户端的相对较小的表上,其性能和查询执行时间达到〜20 +秒,
我的问题是否可以是做同一件事的另一种方法,但是性能最低且查询执行时间短?

最佳答案

根据您的帖子,我认为

Client --- hasOne ----> ClientAssignment  <----- hasMany ---- User
                    [client_id, assigned_id]


因此User可以通过Client拥有很多ClientAssignment

但是,您的client_idassigned_id都在client_assignment表中。因此,您不能像透视表那样使用hasManyThrough

幸运的是,您可以直接计算client_id并获得assigned_id作为user_id,只需使用此数据透视表即可。

查询是这样的(使用distinct(client_id)防止脏记录):

ClientAssignment::whereIn('assigned_id', $users)
                  ->groupBy('assigned_id')
                  ->select('assigned_id AS user_id',
                            DB::raw('COUNT(DISTINCT(client_id)) AS count'))
                  ->get()->toArray();


并添加assigned_id索引以提高性能。

$table->index('assigned_id');

07-27 21:16