LoginSignup
40
46

More than 5 years have passed since last update.

LaravelでN+1問題

Last updated at Posted at 2018-07-03

ネストされたリレーションのN+1問題を回避したいので調査した。

Laravel:5.6.26

例としてERとLaravelのコード

ER

UserController.php
public function index()
{
    $users = User::limit(5)->get();
    return view('user.index')->with('users', $users);
}
index.blade.php
@foreach ($users as $user)  
<p>{{ $user->name }}</p>
<ul>
  @foreach ($user->posts as $post)
  <li>{{ $post->title }}</li>
  <li>コメント数{{ count($post->comments) }}</li>
  @endforeach
</ul>
@endforeach

結果、下記の様なselect文が発行される

select * from users limit 5
select * from posts where posts.user_id = 1
select * from comments where comments.post_id = 10
select * from posts where posts.user_id = 2
select * from comments where comments.post_id = 20
select * from posts where posts.user_id = 3
select * from comments where comments.post_id = 30
select * from posts where posts.user_id = 4
select * from comments where comments.post_id = 40
select * from posts where posts.user_id = 5
select * from comments where comments.post_id = 50

N+1問題を回避するためにwithを使う

UserController.php
public function index()
{
    $users = User::with('posts')->limit(5)->get();
    return view('user.index')->with('users', $users);
}
select * from users limit 5
select * from posts where posts.user_id in (1, 2, 3, 4, 5)
select * from comments where comments.post_id = 10
select * from comments where comments.post_id = 20
select * from comments where comments.post_id = 30
select * from comments where comments.post_id = 40
select * from comments where comments.post_id = 50

postsは回避されたがcommentsがまだ

withでドット指定

UserController.php
public function index()
{
    $users = User::with('posts.comments')->limit(5)->get();
    return view('user.index')->with('users', $users);
}
select * from users limit 5
select * from posts where posts.user_id in (1, 2, 3, 4, 5)
select * from comments where comments.post_id in (10, 20, 30, 40, 50)

ネストされたリレーション先のcommentsまで対応できる

RailsのbulletみたいなやつがLaravelにあるといいんだけど無いっぽい。

※プロダクトのコードで試した為に上記コードは記事作成時に手で起こしてあります。コピペしても動かないかも

追記

N+1が発生しているか、発見できるLaravel N+1 Query Detectorってライブラリがあったようです
LaravelでN+1を検出させる

40
46
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
40
46