Laravel Performance Tips: Count Optimization, Avoiding N+1, and Polymorphic Relationships
Tahsin Abrar

Tahsin Abrar @tahsin000

Joined:
May 17, 2023

Laravel Performance Tips: Count Optimization, Avoiding N+1, and Polymorphic Relationships

Publish Date: Jun 12
5 1

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:

  1. Count optimizations in Eloquent
  2. Avoiding the dreaded N+1 problem with withCount
  3. Structuring withCount queries
  4. 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();
Enter fullscreen mode Exit fullscreen mode

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!
}
Enter fullscreen mode Exit fullscreen mode

✅ 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
}
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

Step 2: Define the relationship in your models

In Image.php:

public function imageable()
{
    return $this->morphTo();
}
Enter fullscreen mode Exit fullscreen mode

In Post.php, Comment.php, and User.php:

public function images()
{
    return $this->morphMany(Image::class, 'imageable');
}
Enter fullscreen mode Exit fullscreen mode

Example Usage:

$post = Post::find(1);
$post->images()->create(['url' => 'example.jpg']);

$user = User::find(1);
$user->images()->create(['url' => 'avatar.png']);
Enter fullscreen mode Exit fullscreen mode

You now have a flexible way to attach images to any model, without multiple image tables.

Comments 1 total

  • Thomas
    ThomasJun 12, 2025

    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!

Add comment