Finding N+1 Queries in Laravel with Perfbase
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 totalHow 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/laravelAdd your API key to .env:
PERFBASE_ENABLED=true
PERFBASE_API_KEY=your-api-keyAdd 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
- Laravel integration guide: full setup, middleware, queue profiling, and configuration
- Understanding flame graphs: how to read and navigate flame graphs
- Create a free account: start profiling in under 5 minutes
Building Perfbase - PHP performance monitoring for teams. Passionate about making PHP applications faster and more observable.
Ready to profile your PHP application?
Every feature included free. No credit card required.