Stop the N+1 query problem in its tracks. Learn how to use eager loading in Laravel to keep your application fast and efficient as your data grows.
Previously in this course, we covered the introduction to database relationships in Laravel, where we defined how our User and Task models interact. In this lesson, we are going to move beyond simply defining those relationships and learn how to query them efficiently.
When you start fetching related data, you'll inevitably run into the "N+1" problem. If you’ve ever noticed your application slowing down as you add more records, this is almost certainly the culprit.
Imagine you want to display a list of all your tasks, along with the name of the user who created each task. If you do this in a loop, your code might look like this:
PHP#6A9955">// In your controller $tasks = Task::all(); #6A9955">// In your Blade view @foreach ($tasks as $task) <p>{{ $task->title }} - Created by: {{ $task->user->name }}</p> @endforeach
On the surface, this looks correct. However, here is what happens under the hood:
SELECT * FROM tasks).SELECT * FROM users WHERE id = ?).If you have 50 tasks, you are firing 51 queries to the database (1 + 50). This is the N+1 problem. As your application scales, this will destroy your performance.
Eager loading tells Laravel to fetch the related models upfront using a single additional query. Instead of running a query inside the loop, Laravel will perform two queries total: one for the tasks and one for all the users associated with those tasks.
To implement this, we use the with() method in our controller:
PHP#6A9955">// Optimized controller code $tasks = Task::with('user')->get();
By adding with('user'), Laravel intelligently gathers all the user_id values from the tasks and executes a single query like SELECT * FROM users WHERE id IN (1, 2, 3...). The performance difference is massive, especially when dealing with hundreds or thousands of records.
Sometimes you don't just want to load related data; you want to filter your results based on them. For example, in our Task Manager, you might want to show only tasks that have a specific category or only tasks where the user is an "admin."
We use the has() or whereHas() methods for this.
has()If you want to retrieve only tasks that have at least one comment (assuming you added a comment relationship later):
PHP$tasks = Task::has('comments')->get();
whereHas()This is more powerful because it allows you to add constraints to the related model. Suppose you want to find all tasks created by users whose name starts with "John":
PHP$tasks = Task::whereHas('user', function ($query) { $query->where('name', 'like', 'John%'); })->get();
This allows you to perform complex filtering without manually joining tables, keeping your code readable and maintainable.
TasksController in your Task Manager project.user relationship using Task::with('user')->get().tasks/index.blade.php file and ensure you are displaying the user's name.with() for every relationship by default. Only load what you actually need in the view. Loading unnecessary data consumes memory and slows down your application.with() must match the exact method name defined in your model. If your method is public function owner(), you must call with('owner'), not with('user').with() there as well, otherwise, your JSON serialization will trigger the same N+1 queries.We’ve covered the essential tools for working with related data:
with): Use this to prevent the N+1 query problem by batch-fetching relationships.whereHas): Use this to filter primary records based on conditions applied to their related models.By mastering these techniques, you ensure your Task Manager remains performant even as your database grows.
Up next: We will dive into Handling File Uploads to allow users to attach files to their tasks.
Learn how to define hasMany and belongsTo relationships in Laravel. Master Eloquent database relationships to link models and access related data with ease.
Read moreStop manually querying the database in your controllers. Learn how route model binding automatically injects Eloquent models into your routes.
Querying Related Data
Debugging with Laravel Tinker
Understanding Service Providers
Using View Composers
Task Manager: Refactoring for Clean Code
Introduction to Testing
Testing Forms and Validation
Using Database Transactions
Handling Global Exceptions
Preparing for Production
Environment Security Best Practices
Managing Assets in Production
Task Manager: Deployment Preparation