神刀安全网

Laravel Eager Loading Demystified

There’s a matter known as the “N + 1 Queries” problem that has long confused web developers to the detriment of their application’s performance. In this post you’ll learn more about the problem, and how easy it is to resolve it using Laravel’s native syntax.

To understand the nature of the issue, consider the following seemingly innocent query:

$users = User::take(5)->get(); 

The take() method is Laravel syntax for limiting the number of returned records. Here’s the query translated into SQLese:

select * from `users` limit 5 

Thanks to Laravel’s fantastic Eloquent ORM , you can pass the query results into your view and easily retrieve data associated via the User model’s associations. Consider for instance a separate State model used to house a list of U.S. states. This State model would be related to User via a HasMany association:

class State extends Model {      public function users()     {       return $this->hasMany('App/User');     }  } 

The User model would be related to State via a BelongsTo association:

class User extends Model {      public function state()     {       return $this->belongsTo('App/State');     }  }  ... 

With this association in place, when the results are passed into the view we can easily retrieve the user’s name and state:

<ul>   @foreach($users as $user)     <li>: </li>   @endforeach </ul> 

Pretty innocent bit of code, right? It certainly seems so until you realize the initial query and ensuring iteration results in the execution of 6 queries ! Thus the name “N + 1”, because we’re executing one query to retrieve the five locations, and then five additional queries to retrieve the name of each user’s state name! This is because Laravel (and all other mainstream frameworks, for that matter) will by default not load each user’s state object until necessary.

In situations where you know you’re going to need to access an associated object you can use the with method to inform Laravel of your intent to do so and therefore preload the data:

$users = User::with('state')->take(5)->get(); 

When you subsequently access a User object’s state name, the data will be immediately available because each user’s state-related data was preloaded along with the original query! We can confirm this by firing up Tinker and comparing the two approaches:

>>> User::take(5)->get(); => Illuminate/Database/Eloquent/Collection {#720      all: [        App/User {#730          id: 1,          email: 'joe@example.com',          name: "Joe Smith",          created_at: "2016-04-05 01:05:37",          updated_at: "2016-04-05 01:05:37",        },        App/User {#730          id: 2,          email: 'mary@example.com',          name: "Mary Smith",          created_at: "2016-04-05 02:05:37",          updated_at: "2016-04-05 02:05:37",        },        ...      ],    } 

And here is the output when with() is used. Note how each user is accompanied by a state object:

>>> User::take(5)->get(); => Illuminate/Database/Eloquent/Collection {#720      all: [        App/User {#730          id: 1,          email: 'joe@example.com',          name: "Joe Smith",          created_at: "2016-04-05 01:05:37",          updated_at: "2016-04-05 01:05:37",          state: App/State {#735            id: 1,            name: 'Ohio'          },        },        App/User {#730          id: 2,          email: 'mary@example.com',          name: "Mary Smith",          created_at: "2016-04-05 02:05:37",          updated_at: "2016-04-05 02:05:37",          state: App/State {#735            id: 2,            name: 'New York'          },        },        ...      ],    } 

There you have it, eager loading demystified! Be sure to incorporate this approach into your applications, I guarantee you’ll see significant performance improvements as a result of making this seemingly minor change.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Laravel Eager Loading Demystified

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮