Laravel8 API Resource Queryの効率化
Laravel8のリレーションシップのQueryをDebugしてみたところ
レコードごとのQueryを実行していたのでQueryを効率化する方法について調べました。
(前提はUserとPostの1:N関係)
まずはLaravelのLoadigの種類について調査
Lazy Loading(怠惰な読込み)
LaravelのデフォルトのLoading方式だが、N+1問題を起こすLoading方式
※N+1問題とは
Lazy LoadingのSQL例
Routeの例
api.php
use App\Http\Resources\PostCollection;
use App\Models\Post;
Route::get('/posts', function () {
return new PostCollection(Post::all());
});
SQL実行例
postの例
SELECT * FROM posts;
SELECT * FROM users WHERE id = 1;
SELECT * FROM users WHERE id = 2;
SELECT * FROM users WHERE id = 3;
...
Eager Loading(熱心な読込み)
Routeの例
api.php
use App\Http\Resources\PostResource;
use App\Models\Post;
Route::get('/posts', function () {
$posts = Post::with(['users']);
return PostResource::collection($posts->paginate(50))->response();
});
PostResource.php
<?php
namespace App\Http\Resources\Post;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Http\Resources\UserResource;
class CustomerResource extends JsonResource
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'users' => UserResource::collection($this->whenLoaded(relationship:'users')),
];
}
}
SQL実行例
postの例
select * from `posts` where `users`.`user_id` in (1, 2, 3)
結論
レコード数分のQueryが1Queryにまとまるのでその分のSqlの接続数が減り、
アプリケーションのパフォーマンスが上がります。
API Resourceのほうには適応したほういいでしょう。