Skip to main content
← Back to blog
Engineering · tutorial laravel n+1

Finding N+1 Queries in Laravel with Perfbase

B
Ben Poulson · Founder
March 28, 2026 · 2 min read

Finding N+1 Queries in Laravel with Perfbase

The N+1 query problem is the single most common performance issue in Laravel applications. It’s also one of the hardest to catch in code review because the code looks perfectly reasonable.

What is an N+1 query?

Consider this controller:

$orders = Order::all(); // 1 query

foreach ($orders as $order) {
    echo $order->customer->name; // N queries (one per order)
}

For 100 orders, this executes 101 queries instead of 2. Each iteration triggers a separate SELECT * FROM customers WHERE id = ?, identical in structure and different only in the parameter value.

The fix is eager loading:

$orders = Order::with('customer')->get(); // 2 queries total

How Perfbase detects N+1 patterns

The Perfbase PHP extension tracks every database query your application executes, including the normalized query text and the call path that triggered it.

During analysis, queries are normalized: literal values, quoted strings, and numeric parameters are replaced with placeholders. Queries that share the same normalized pattern are grouped together. When 5 or more queries match the same pattern within a single trace, Perfbase flags it as a potential N+1.

For example, these 100 queries:

SELECT * FROM customers WHERE id = 1
SELECT * FROM customers WHERE id = 2
SELECT * FROM customers WHERE id = 3
...

All normalize to SELECT * FROM customers WHERE id = ? and get grouped as a single N+1 pattern with a count of 100.

What the console shows you

In the Database Queries panel of any trace, Perfbase shows:

  • N+1 patterns highlighted at the top, sorted by total time spent.
  • The normalized query pattern (e.g., SELECT * FROM customers WHERE id = ?).
  • Repetition count: how many times the pattern was executed.
  • Total time spent across all repetitions and the average time per query.
  • The call path in the function tree where the queries originated.

This makes it easy to see both what the repeated query is and how much time it’s actually costing you. A pattern that runs 200 times at 0.5ms each is burning 100ms of wall time that a single eager load would eliminate.

Setting up Perfbase with Laravel

Install the PHP extension:

bash -c "$(curl -fsSL https://cdn.perfbase.com/install.sh)"

Install the Laravel package:

composer require perfbase/laravel

Add your API key to .env:

PERFBASE_ENABLED=true
PERFBASE_API_KEY=your-api-key

Add the middleware to your application and you’re profiling. Every HTTP request, queue job, and Artisan command is traced automatically. See the Laravel integration guide for full setup details including middleware registration and configuration options.

Beyond N+1: what else Perfbase catches

N+1 queries are just one of the patterns visible in a Perfbase trace. Each trace also gives you:

  • Flame graphs showing where wall time is spent across your entire call stack.
  • Function-level timing with CPU time, memory allocation, and call counts.
  • All database queries with execution and hydration time breakdowns.
  • Outbound HTTP requests, cache operations, and queue interactions.

Next steps

B
Ben Poulson · Founder

Building Perfbase - PHP performance monitoring for teams. Passionate about making PHP applications faster and more observable.

Share this post X / Twitter LinkedIn

Ready to profile your PHP application?

Every feature included free. No credit card required.