KoudouBlogs

元警察官 / 現ITエンジニア 宅トレ発信

『Laravel』N+1問題とEager Loading

アイキャッチ
laravel.com

N+1問題とは「Lazy Loading」

Eloquentモデルのリレーションの呼び出しは「Lazy Loading」

そのプロパティが呼ばれてからSQLが実行される。

<?php
$animais = Animal::all(); // select * from animals; (+1回)
foreach ($animals as $animal) {
   $animal->owner->name;  // select * from owners where id = $animal->owner_id (N回)
}

SELECT文(ownersテーブルへの問い合わせクエリ)が取得件数分だけ実行されてしまうので、時に重大なパフォーマンス低下を引き起こすんや。 これがN+1問題や。

N+1問題を解決する「Eager Loading」とは

リレーション元のモデルを取得直後に、関連する子モデルのデータを全て取得しておくこと。
Eager Loadeingにはwithメソッドを利用する。
引数にはプロパティ名を指定する。

<?php
$animais = Animal::with('owner')->get(); // select * from animals; (1回)
foreach ($animals as $animal) {
   $animal->owner->name;  // select * from owners where id in (1,2,3,.....)   (1回)

with句を使うことでクエリの実行が2回で済むんやな。

「Eager Loading」複数リレーションの場合

with句の引数にリレーション先のプロパティ名を複数渡す。

<?php
$animais = Animal::with('owner','country')->get(); 
foreach ($animals as $animal) {
   $animal->owner->name; 
   $animal->country->name; 
}

「Eager Loading」リレーション先のリレーション先を取得する場合

with句の引数でドット記法を使う。

<?php
$animais = Animal::with('owner','owner.tel')->get(); 
foreach ($animals as $animal) {
   $animal->owner->name; 
   $animal->owner->tel->tel_number; 
}

「Eager Loading」対象をクロージャで絞り込む

<?php
 $owners = Owner::with ([
 'animals' => function($query) {
  $query->where('***')->orderBy('***');
 }
 ])->get();

 foreach ($owners as $owner) {
  foreach ($owner->animals as $animal) {
     echo $animal->name; 
  }
 }
PVアクセスランキング にほんブログ村