2017-01-24 21 views
0

私は次の関係を持っています:雄弁を使用して大きなデータセットからカウントを照会

ジョブには多くのロールがあります。

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); 
} 

特定のステータスを持つすべての割り当ての数を取得する必要があります。「承認済み」とします。これらのカウントによって、アプリケーションの実行が非常に遅くなっています。ここで私はそれをやっている方法です:

foreach ($job->roles as $role){ 
    foreach ($role->shifts as $shift) { 
     $pendingCount = $shift->assignments()->whereStatus("Pending")->count(); 
     $bookedCount = $shift->assignments()->whereIn('status', ["Booked"])->count(); 
    } 
} 

私は確かに、より良い、より速い方法が必要です。これらのクエリの中には、30秒以上かかるものもあります。私が知っている何十万という課題がパフォーマンスに影響しています。どのようにこれらのクエリを高速化できますか?

+0

あなたは熱心なロードを見て撮影したことがありますか? https://laravel.com/docs/5.1/eloquent-relationships#eager-loadingキーワード 'with'を使用して、複数のクエリではなく1つのクエリで必要な関係を持つモデルを読み込みます。 –

+0

私はそれを調べましたが、この場合、どちらのモデルに熱心にロードすべきかはわかりませんでした。私は熱心な仕事の仕事への移行はできませんでしたか?そこには関係はありません。 –

答えて

1

ここでN + 1号に数回出ています。ネストされた代入をジョブで遅延ロードしたい場合は、リレーションにアクセスすることができます。とwhereIn()呼び出しはクエリビルダーではなく返されたコレクションで実行されます。なぜならこの例ではwhereStatus("Pending")ではなくwhere('status', "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(); 
} 

これはすばやく必要です。あなたもその一歩取り、結果をマッピングし、役割のプロパティで結果を格納することができ

UPDATE

$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; 
}); 
+0

これを調べると、報告が返ってきます。ありがとう! –

+0

私を正しい道につけてください、ありがとうございました。 –