はじめに
現在、laravelを使ってWebアプリの開発をしております。
実務中にfirst()メソッドを使ってデータを取得する際に、インスタンスの内容が変更してしまう現象が起きてしまいました。
原因を調べてみると、Eager LoadingとN+1問題が関わっていることが判明しました。
そのEager LoadingとN+1問題を実例とともに簡単にまとめました。
目次
1.環境
2.実際に起こった現象
3.Eager Loadingとは?
4.N+1問題とは?
5.Eager Loadingを使った解決策
5.まとめ
1.環境
PHP 8.0.10
Laravel Framework 8.83.25
2. 実際に起こった現象
下記のようにデータを取得しようとした時に起こりました。
$users = User::query()
->whereIn('id', $userIds)
->where('group_id', auth()->user()->group_id)
->get();
// $users①
$group = $users->first()->group;
// $users②
この場合に、$users①のデータと$users②のデータの内容が違っており、これ以降の機能がおかしくなってしまったのです。
調べてみるとEager Loadingが関係しているとのことでしたので、下記でまとめています。
3. Eager Loadingとは?
Eloquentモデルを使用してデータベースから複数のテーブルから取得したい時に、関連するモデルを1度のクエリで取得することができるテクニックです!
クエリの回数を減らすことができるため、パフォーマンスの向上のみならず「N+1問題」の解消にもなります!
使い方
with関数
1. モデルにリレーションを定義する
public function group(){
return $this->belongsTo(Group::class);
}
2. データを取得するときにwith関数を使う
$users = Users::with('group')
->whereIn('id', $userIds)
->where('group_id', auth()->user()->group_id)
->get();
4. N+1問題とは?
先ほど、Eager Loadingのところでも少し出てきたN+1問題とはどういう現象かを簡単にご説明します。
関連した複数のモデルに紐づいたデータを取得する際に、余分のクエリを走らせてしまい、少なからず表示速度等に悪影響を出してしまうことを言います。
例えば、顧客情報を取得する際に、それぞれの顧客に関連する注文情報を取得するためにN回のクエリが必要な場合、N+1問題が発生します。これにより、データベースへの負荷が高まり、アプリケーションの速度が低下します。
この問題の構図
N+1問題を解消したい→→→→→→Eager Loadingで対応しよう!
5.Eager Loadingを使った解決策
今まで記載してきたものを踏まえると下記のようにコードを直すとよさそうです。
$users = User::with('group')
->whereIn('id', $userIds)
->where('group_id', auth()->user()->group_id)
->get();
// $users①
$users = $users->first()->group;
// $users②
このように修正することで、$users①と$users②は同じデータになると思います!
まとめ
この記事では、Laravel EloquentでのEager LoadingとN+1問題に焦点を当て、first()メソッドを通じて発生する問題とその解決策をまとめてみました。
Eager Loadingを適切に活用することで、パフォーマンスの向上につながる且つ難しくもないので積極的に活用してより良いアプリ開発をしていきたいですね。
ご清覧いただきありがとうございました!