I knew that this problem N+1 is one of the problems that affect the performance of my project and I found this article that contains the reasons https://laravel-news.com/laravel-n1-query-problems and solution to this problem and I wanted to share it with you because of the importance of this topic
Four cases to clarify the problem and solve it
- Case 1. "Regular" N+1 Query
// app/Models/Book.php class Book extends Model { public function author() { return $this->belongsTo(Author::class); } } // Then, in some Controller: $books = Book::all(); foreach ($books as $book) { echo $book->author->name; }
fix
// Instead of $books = Book::all(); // You should do $books = Book::with('author')->get();
- Case 2. Two Important Symbols
public function index() { $authors = Author::with('books')->get(); return view('authors.index', compact('authors')); } // Blade @foreach($authors as $author) <tr> <td>{{ $author->name }}</td> <td>{{ $author->books()->count() }}</td> </tr> @endforeach
So, the method of relation would query the database for each author. But if you load the data, without () symbols, it will successfully use the eager loaded data $author->books
fix
// Controller $authors = Author::withCount('books')->get(); // Blade {{ $author->books_count }}
- Case 3. "Hidden" Relationship in Accessor
// Controller public function index() { $authors = Author::all(); return view('authors.index', compact('authors')); } // Blade @foreach($authors as $author) <tr> <td>{{ $author->name }}</td> <td>{{ $author->is_active ? 'Yes' : 'No' }}</td> </tr> @endforeach
That "is_active" is defined in the Eloquent model
use Illuminate\Database\Eloquent\Casts\Attribute; class Author extends Model { public function isActive(): Attribute { return Attribute::make( get: fn () => $this->books->count() > 0, ); } }
- Case 4. Be Careful with Packages
Laravel has a great ecosystem of packages, but sometimes it's dangerous to use their features "blindly". You can run into unexpected N+1 queries if you're not careful.
- The Built-In Solution Against N+1 Query
since Laravel 8.43, the framework https://laravel-news.com/disable-eloquent-lazy-loading-during-development
In addition to the Laravel Debugbar for inspection, you can add a code to the prevention of this problem
You need to add two lines of code to app/Providers/AppServiceProvider.php
use Illuminate\Database\Eloquent\Model; class AppServiceProvider extends ServiceProvider { public function boot() { Model::preventLazyLoading(! app()->isProduction()); } }
Now, if you launch any page that contains an N+1 Query problem, you will see an error page
I have explained only the important points, but to go deeper, the article must be increased and benefited from.
Top comments (0)