If you've been working with Laravel and MySQL for a while, you've probably hit some common performance pitfalls—like slow queries, N+1 problems, and inefficient use of relationships.
Today, let's walk through some real-world strategies to optimize your Laravel app using:
- Count optimizations in Eloquent
- Avoiding the dreaded N+1 problem with
withCount
- Structuring
withCount
queries - Using polymorphic relationships effectively
Let’s dive in. 🏊♂️
1️⃣ Count Optimization in MySQL with Laravel
Many Laravel developers tend to do this:
$post = Post::find(1);
$commentCount = $post->comments()->count();
While this works fine, if you're doing it inside a loop or multiple times, it executes a separate SQL query each time, which adds up quickly. Imagine a page with 10 posts—yep, that’s 11 queries: one for posts and one per post’s comments.
Better approach: Use withCount()
to optimize this.
2️⃣ Avoid the N+1 Problem with withCount
The N+1 problem is when one query is used to get the initial dataset, but additional queries are executed for related data. Laravel gives us a simple fix:
$posts = Post::withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count; // no extra queries here!
}
✅ Result: 1 query instead of N+1.
Laravel adds a comments_count
attribute to each post behind the scenes.
3️⃣ Using withCount
with Conditions
Want to get counts with specific conditions? You can pass a closure to withCount()
:
$posts = Post::withCount(['comments' => function ($query) {
$query->where('is_approved', true);
}])->get();
foreach ($posts as $post) {
echo $post->comments_count; // Only approved comments
}
This is super useful for dashboards, analytics, or anywhere you need conditional counts.
4️⃣ Polymorphic Relationships: One Table to Rule Them All
What if you want to associate images with multiple models like Post
, Comment
, and User
?
Laravel makes this easy with polymorphic relationships.
Step 1: Create the images
table with imageable_id
and imageable_type
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->string('url');
$table->morphs('imageable'); // Adds imageable_id & imageable_type
$table->timestamps();
});
Step 2: Define the relationship in your models
In Image.php
:
public function imageable()
{
return $this->morphTo();
}
In Post.php
, Comment.php
, and User.php
:
public function images()
{
return $this->morphMany(Image::class, 'imageable');
}
Example Usage:
$post = Post::find(1);
$post->images()->create(['url' => 'example.jpg']);
$user = User::find(1);
$user->images()->create(['url' => 'avatar.png']);
You now have a flexible way to attach images to any model, without multiple image tables.
Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.