
Laravelにはモデルを扱うためのEloquentというORMがあります。おかげさまで、こまごましたコードを書かなくても、直感的にデータベースの操作を行うことができます。
しかし、よく切れるナイフをふるうにはそれなりの技術が必要です。
Laravelのもつポテンシャルを最大限に引き出すために、少しふみ込んで調査してみましょう。
今回は、知らなければついやってしまう「N+1問題」についてがテーマです。
N+1問題とは?
Laravelはサボり上手
Laravelには、効率よくデータを扱うためにLazyLoadという機能があります。
これは、データが必要になったときに、都度データベースにアクセスすることで、不要なデータを取得しないようにする機能です。
例えば、Userに紐づくPostモデルがあるとします。さらにPostには複数のCommentがつくとします。以下のようにUserのリレーションからすべてのPostを取得できますが、PostごとにあるCommentはViewで使用されていません。このとき、無用なCommentをわざわざデータベースから持ってくるのはめんどくさい!必要になったら取りいくわ!というのがLazyLoadです。
1 2 3 4 5 6 7 |
//UserController.php //ユーザーの情報を表示する public function show(Request $request, $id) { $user = User::find($id); return view('user.show', compact('user')); } |
1 2 3 4 5 6 |
//user/show.blade.php //Postの一覧を表示する @foreach ($user->posts as $post) // Userに紐づくPostを取得 <li>Title : {{ $post->title }}</li> <li>Contents : {{ $post->contents }}</li> @endforeach |
なかなか賢いですね。
怠惰の代償
しかし、Lazyであることによる失敗もあります。
先ほどの例で、PostのCommentを表示する場合、問題が発生します。
1 2 3 4 5 6 7 8 9 10 |
//user/show.blade.php //Postの一覧を表示する @foreach ($user->posts as $post) // Userに紐づくPostを取得 <li>Title : {{ $post->title }}</li> <li>Contents : {{ $post->contents }}</li> @foreach ($post->comments as $comment) //PostごとにCommentを取得するクエリが発行される! <li>Date : {{ $comment->created_at }}</li> <li>Comment : {{ $comment-\>;message }}</li> @endforeach @endforeach |
先を見越してCommentも取得しておけば、1度データベースにアクセスするだけで済みます。
Lazyであるがゆえに、無駄に多くデータベースに足を運ぶようになってしまいました。
Postsを取得するクエリ(1回) + PostごとのCommentを取得するクエリ(N回)が発行されることから「N+1問題」と呼ばれています。
データベースへのアクセスは、それなりの負荷がかかるため、Nが大きくなればなるほどパフォーマンスが下がってしまいます。レスポンスが遅くなれば、SEOでも不利になってしまいます。
対策
EagerLoadを使用することで、N+1問題を回避できます。Userを取得する際に、withを使うことで先にPostやCommentを取りに行っておきます。
1 2 3 4 5 6 7 |
//UserController.php //ユーザーの情報を表示する public function show(Request $request, $id) { $user = User::with('posts', 'posts.comments')->find($id); return view('user.show', compact('user')); } |
気を付けないと、うっかりやってしまいそうです。
おせっかいで、なんでも先回りしてやってくれるLaravelですが、たまには失敗することもあります。きちんと理解してうまく扱ってあげましょう!

Company運用会社
株式会社トランソニックソフトウェア

名古屋市でシステム開発・WEB制作を中心に事業を展開しています。システムに関すること、なんでもお気軽にご相談ください!