N+1 Problem in Doctrine & Eloquent
Also Known As
ORM N+1
Eloquent N+1
lazy load N+1 ORM
TL;DR
Accidentally issuing one query per related entity instead of one JOIN — the most common ORM performance pitfall, solved by eager loading.
Explanation
The N+1 problem: fetching N orders then calling $order->customer inside a loop fires N additional queries — one per order — instead of a single JOIN. In Doctrine: use DQL JOIN FETCH or addSelect on a QueryBuilder to eager-load associations. In Eloquent: use with('customer') on the query. Detect N+1 in development with Laravel Telescope, Debugbar, or Clockwork (all show per-request query counts). In Doctrine enable SQL logging to a file. A page making 300 queries that should make 3 is the signature. Fix: identify the loop, move the JOIN upstream, verify query count drops. For deeply nested associations, consider a dedicated read-model query bypassing the ORM entirely.
Common Misconception
✗ ORMs automatically optimise relationship loading. ORMs default to lazy loading — each relationship access on a collection item triggers a separate query. Always use eager loading (with() in Eloquent, fetch JOIN in Doctrine) when rendering collections with related data.
Why It Matters
ORMs make N+1 queries invisible — the code looks like one operation but triggers hundreds of queries, each with network round-trip overhead that adds up to seconds of latency.
Common Mistakes
- Not enabling ORM query logging in development — N+1 queries are silent without it.
- Lazy-loaded relationships in loops — the classic ORM N+1 pattern.
- Using with() for eager loading but then accessing a non-eager-loaded relationship inside the loop.
- Not using tools like Laravel Debugbar or Symfony Profiler to detect query counts per request.
Code Examples
✗ Vulnerable
$orders = $em->findAll(Order::class); // 1 query
foreach ($orders as $o) {
echo $o->getCustomer()->getName(); // N queries!
}
✓ Fixed
$orders = $em->createQuery(
'SELECT o, c FROM Order o JOIN FETCH o.customer c'
)->getResult(); // 1 query
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
29
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 1
No pings yesterday
Amazonbot 8
ChatGPT 4
Perplexity 3
Google 3
Unknown AI 2
Ahrefs 2
Majestic 1
Also referenced
How they use it
crawler 23
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Low
⚡ Quick Fix
Enable Laravel's strict mode (Model::preventLazyLoading()) or Doctrine's lazy loading profiler in development — they throw exceptions when you accidentally trigger lazy loads in loops
📦 Applies To
PHP 7.0+
web
cli
laravel
doctrine
🔗 Prerequisites
🔍 Detection Hints
Eloquent relation accessed in foreach without eager load; Doctrine proxy object loaded per iteration; Debugbar showing 50+ identical queries
Auto-detectable:
✓ Yes
laravel-debugbar
laravel-strict-mode
doctrine-profiler
clockwork
⚠ Related Problems
🤖 AI Agent
Confidence: High
False Positives: Medium
✗ Manual fix
Fix: Medium
Context: File
Tests: Update