はじめに
LaravelでEloquent ORMを使っていると、知らず知らずのうちに N+1クエリ問題 に陥ることがあります。
本記事では、この問題を根本から解決する Eager Loading(イーガーローディング) というテクニックをわかりやすく解説します。
1. Eager Loadingとは?
Eager LoadingはEloquent ORMの機能の一つで、親モデルのクエリが実行された直後に、
関連するリレーションも一緒にクエリする仕組みです。
これにより、Eloquentのリレーションシップで発生しがちな「N+1クエリ問題」を解消することができます。
N+1クエリ問題とは?
デフォルトでは、Eloquent ORMのリレーションシップはプロパティとしてアクセスされたときに
初めてクエリが実行されます。このため、ループ内でリレーションにアクセスすると
「N+1クエリ問題」が発生します。
Book モデルが Author モデルとリレーション(1冊の本は1人の著者に属する)を持つ例:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
/**
* この本を書いた著者を取得する
*/
public function author()
{
return $this->belongsTo(Author::class);
}
}
通常の方法で全ての本とその著者情報を取得する場合:
use App\Models\Book;
$books = Book::all();
foreach ($books as $book) {
echo $book->author->name;
}
10冊の本がある場合、このコードは 合計11回 のクエリを実行します。
- 全10冊を取得する:1クエリ
- 各本の著者を取得する:10クエリ
これが 「N+1クエリ問題」 です。
Eager Loadingを使えば、同じ処理が わずか2クエリ で済みます!
2. Eager Loadingの使い方
基本的な使い方
with メソッドを使ってEager Loadingを利用できます。
$books = Book::with('author')->get();
foreach ($books as $book) {
echo $book->author->name;
}
発行されるSQLクエリ:
select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)
複数のリレーションをまとめてEager Load
$books = Book::with(['author', 'publisher'])->get();
ネストされたリレーションをEager Load
Book → Author → Contact のようにネストされている場合:
$books = Book::with('author.contacts')->get();
取得するカラムを指定する
デフォルトでは全カラム(SELECT *)が取得されますが、必要なカラムだけを指定できます。
// authorのidとnameだけを取得
$books = Book::with('author:id,name')->get();
常にEager Loadする設定
モデルの $with プロパティに設定することで、常にEager Loadingを適用できます。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
/**
* 常にロードするリレーションシップ
*
* @var array
*/
protected $with = ['author'];
public function author()
{
return $this->belongsTo(Author::class);
}
}
特定のクエリでEager Loadingを除外する
without メソッドで、デフォルトのEager Loadingを除外できます。
$books = Book::without('author')->get();
条件付きEager Loading
クロージャを使って、リレーションに条件を付けることもできます。
use App\Models\User;
$users = User::with(['posts' => function ($query) {
$query->where('title', 'like', '%code%');
}])->get();
まとめ
| 方法 | クエリ数 |
|---|---|
| 通常のリレーション(N+1) | N+1回 |
Eager Loading(with) |
2回 |
Eager Loadingを理解して活用することで、LaravelアプリケーションのDBパフォーマンスを
大幅に改善できます。ぜひ積極的に使ってみてください!