Find N+1 queries in a Laravel snippet
Run an Eloquent snippet in LaraBench, then compare its SQL before and after adding withCount() or eager loading.
Direct answer
To find an N+1 query from Tinker, run a deliberately small Eloquent snippet, inspect the SQL it produces, then replace repeated relationship queries with eager loading or aggregate counts. LaraBench records the snippet, output, and captured SQL together in History.
When to use this
Use this when a page, job, export, or API endpoint feels slower than expected and you can reproduce its database access with a small snippet. Keep the sample size low so the repeated query pattern is easy to read.
Terminal approach
In the terminal, boot the same Laravel app and run a tiny snippet through Artisan Tinker. Laravel can listen for database queries in application code. From Tinker, reproduce the Eloquent access pattern and compare the result shape before changing it.
php artisan tinker
App\Models\User::query()->latest()->limit(20)->get();If the app only boots inside Docker or Sail, use the matching container command from the Docker workflow first.
LaraBench approach
- Open Run Code and choose the right connection.
- Paste the first snippet and run it in Tinker mode.
- Open the SQL queries panel for the run.
- Look for the same query shape repeated once per model row.
- Run the fixed snippet and compare the captured SQL count.
LaraBench query analysis can flag duplicate queries and likely N+1 patterns. Treat the warning as a pointer to inspect, then confirm the fix by rerunning the snippet.
Snippet
This example intentionally accesses a relationship count through the relationship method inside a loop. Replace User and orders with models from your app.
use App\Models\User;
$users = User::query()->latest()->limit(20)->get();
return $users->map(fn (User $user) => [
'id' => $user->id,
'email' => $user->email,
'orders' => $user->orders()->count(),
]);Then compare it with an aggregate count:
use App\Models\User;
$users = User::query()
->withCount('orders')
->latest()
->limit(20)
->get();
return $users->map(fn (User $user) => [
'id' => $user->id,
'email' => $user->email,
'orders' => $user->orders_count,
]);Expected result
The first run often shows one users query plus repeated count queries. The second run should produce the same output shape with a lower query count. The exact SQL depends on your database driver, scopes, indexes, and relationship definitions.
Troubleshooting
- If the model class is not found, use your app's real namespace or import the model at the top of the snippet.
- If the SQL panel is empty, confirm query capture is enabled for the selected LaraBench run and that the snippet touches the database.
- If the fixed version changes the result, check global scopes, soft deletes, and relationship constraints before accepting the change.
Safety notes
Keep the snippet read-only. Avoid calling relationship methods that create, update, delete, dispatch jobs, or fire business side effects while you are only trying to inspect SQL.
Related workflows
Pair this with the Eloquent benchmark workflow after you have reduced the query count. If the app runs in Docker, start with the Docker Tinker workflow.
Run these checks in LaraBench.
The free app includes Run Code, Artisan commands, Docker and SSH connections, saved items, History, logs, and benchmarks.