3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Laravel]withメソッドでN+1問題を解決する

Posted at

はじめに

Laravelではリレーション定義を行ったモデルを使用することでN+1問題が発生します。

今回はN+1問題を解決するためにwithメソッドを利用したので、備忘録として残しておきます。

環境

  • Laravel:8.83.4

1. withメソッドとは

取得したModelインスタンスのリレーション先を事前に取得するメソッドです。
Eagerロード」によってN+1問題を解決するために利用されます。

2. N+1問題を解決する

今回はUserモデルに以下のようなリレーションを定義して進めていきます。

Userモデル
app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
//略
    /**
     * リレーション - postsテーブル
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
//略
}


まずはwithメソッドを使わずにデータを取得する場合から見ていきます。

2-1. withメソッドを使わない場合

全ユーザーを取得した後に、動的プロパティでユーザーに紐づく投稿記事をそれぞれ取得しています。

UserController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        $users = User::all();

        foreach ($users as $user) {
            $user->posts;
        }
    }
}

動的プロパティにはリレーション先のプロパティが参照されるまでロードされないという性質があります。
そのため、今回の場合でいうと、ユーザーの数が増えるにつれてクエリの発行回数も増えていきます。
このようなN+1問題によるパフォーマンスの低下を招かないための対策としてwithメソッドを利用します。

2-1. withメソッドを使う場合

withメソッドEagerロードすることでN+1問題を解決します。

UserController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        $users = User::with('posts')->get();//変更

        foreach ($users as $user) {
            $user->posts;
        }
    }
}

今回の場合、ユーザー情報だけでなく投稿記事も一括で取得することでクエリの発行回数を減らしています。
withメソッドを使うことで、ユーザーの数が増えても、
usersテーブルのデータを取得するクエリとpostsテーブルのデータを取得するクエリ、計2回のクエリしか発行されません。
このようにして事前にリレーション先のデータを取得することでN+1問題を解決することができます。

以上で実装完了です。
N+1問題はWebシステムのパフォーマンス悪化につながるので、普段から意識しながらコードを書いていきたいです。

3. 参考文献

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?