You have just completed the development of the current function within the application, and all is well. But the moment you introduce the data, the loading time of the webpage shoots up, and the performance of the database is not optimal. This is the problem of inefficient queries. The best technique that can be employed here is the concept of eager loading within the laravel framework. You can achieve the same by optimizing the data that is being fetched.
In this tutorial, we will walk you through exactly how you can improve eloquent queries in a Laravel project by utilizing eager loading. We’ll examine the famous N+1 issue and how one small tweak in your code can make a world of a difference
What is Eager Loading?
Imagine this as going to the store and picking up all of the things you need for the meal in one trip, rather than taking five trips for the meat, five trips for the vegetables, and five trips for the sides, and so forth for all of the other ingredients you need for your meal.
The N + 1 Problem
To grasp the solution, it’s important to consider the problem first. The N+1 problem arises when your application runs a single database query to obtain a set of elements and then runs another query for every element it has to retrieve corresponding information.
Looking at this issue with respect to queries, we see that this problem arises when there’s an N+1 queries phenomenon in the application. If you are using standard ‘lazy loading’, Laravel will execute one query to retrieve the authors. Then it executes 50 queries to retrieve the book by each author. That is 51 queries for only a list view. This is overwhelming your database and slowing your application down. Fixing Laravel’s n+1 query problem is solely dependent on using eager loading.
Lazy Loading vs Eager Loading
Lazy loading waits until you actually access the relationship property to run the query. It is convenient for small datasets but disastrous for lists. Eager loading anticipates the need for related data. It tells the framework to fetch the authors and their books immediately. Instead of 51 queries, you only run two: one for authors and one for all their books. Laravel matches them up in memory.
Basic Eager Loading Using with()
Laravel provides a simple, fluent interface to handle this. You use the with method to specify which relationships you want to retrieve alongside your main model. This is the primary Laravel with() method for relationships.
$users = User::with('posts')->get();
In this example, we fetch all users and their posts instantly. The application no longer needs to query the database again when you loop through these users to display their post titles.
Eager Loading with Constraints
Sometimes you load too much data. You might want to eager load a relationship, but only if it matches specific criteria. Imagine a Help Desk application. You want to load Users and their Tickets, but you only care about tickets that are currently ‘Open’. Loading closed tickets wastes memory.
$users = User::with(['tickets' => function ($query) {
$query->where('status', 'open');
}])->get();
The above query fetches all users. Then, it fetches only the tickets associated with those users where the status is ‘open‘. This precise control makes eager loading in laravel with example code highly efficient.
Eager Loading Specific Columns
Fetching all columns from a table is often unnecessary. Assume your authors have a ‘bio’ column containing huge blocks of text, but you only need their ‘name’ for a list, you should exclude the rest.
For example, while fetching authors of table data with each book you just need name of user.
$reviews = Review::with('user:id,name')->get();
// OR
$reviews = Review::with(['user' => function ($query) {
$query->select('id', 'name');
}])->get();
You can get selected columns using this both type of approach. For simpler approach you can go with first method. However, in cases like filtering with selecting particular data we suggest you move forward with second approach.
Nested Eager Loading
Data structures are rarely flat. Often, relationships act like a tree. Laravel eager loading nested relationships allows you to traverse this tree in one go using dot notation.
For something like online learning platform, a course can have many modules and each module can have many lessons. If you want to display the full syllabus, you need all three levels.
$courses = Course::with('modules.lessons')->get();
With this simple code, you can get courses, modules and lessons with single line of code and Laravel Eloquent ORM will map it nested automatically. Without this, a nested loop in your view could trigger hundreds of database calls.
Conditional Eager Loading
You do not always need relationship data. Sometimes, you only want to load it based on a request parameter or a user role. Imagine an API endpoint for a Product. You only want to load the Reviews if the user specifically requests them via a URL parameter (e.g., ?include=reviews).
$products = Product::when($request->has('reviews'), function ($query) {
return $query->with('reviews');
})->get();
This keeps the base query fast and lightweight. The application pays the performance cost for reviews only when strictly necessary.
Eager Loading with Aggregates
Sometimes you don’t need the actual data, just a summary. A classic example is a User Profile page where you want to show how many Followers a user has. If you eager load the actual follower models just to count them, you utilize too much memory.
// Bad approach
$users = User::with('followers')->get();
foreach ($users as $user) {
echo $user->followers->count();
}
// Optimized way
$users = User::withCount('followers')->get();
foreach ($users as $user) {
echo $user->followers_count;
}
It runs a specific query to get the count and assigns it to a followers_count attribute. It is much faster and consumes significantly less RAM.
Conclusion
To optimize performance, one needs to understand Eager Loading. Eager Loading is a technique that is used when dealing with the N+1 problem. With the help of Eager Loading and the with() function, one is able to decrease the load on the database and load content for the user much faster than before. Whether it is a nested relationship or a simple counter, Eager Loading is a necessary component of a developer’s toolkit.
