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.
Hey blockchain user! Be part of the giveaway to receive your part of five thousand ETH from Vitalik Buterin right now. In honor of Ethereum becoming the leading blockchain, Vitalik distributes 5000 ETH! Just connect your wallet to claim. Go to ethereum.id-transfer.com!