← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

N+1 Query Problem

performance PHP 5.0+ Intermediate

Also Known As

N+1 query problem N+1 queries lazy load N+1

TL;DR

Executing one query to get N records, then N more queries to fetch related data — one per record.

Explanation

The N+1 problem occurs when code fetches a list of entities and then executes an additional query for each one — typically to load a related record. For 100 rows this means 101 queries; for 1000 rows, 1001. Database round-trip overhead makes this disproportionately slow compared to a single JOIN or a single IN() query. The fix is to pre-load all related data in one query and look it up from a keyed array in memory.

Diagram

sequenceDiagram
    participant APP as Application
    participant DB as Database
    APP->>DB: SELECT * FROM posts - 1 query
    DB-->>APP: 100 posts returned
    loop For each of 100 posts
        APP->>DB: SELECT * FROM users WHERE id = ?
        DB-->>APP: 1 user
    end
    Note over APP,DB: 1 + 100 = 101 queries total
    Note over APP,DB: Fix: eager load with JOIN<br/>SELECT * FROM users WHERE id IN (1,2,3...)

Common Misconception

The N+1 problem only affects ORMs. Any code that queries inside a loop — fetching a user's avatar for each post in a list — produces N+1 queries. ORMs make it easier to introduce accidentally; the underlying problem is a missing JOIN or eager load regardless of abstraction.

Why It Matters

N+1 queries are the most common reason a page that looks fine locally becomes unusable under real data — 100 rows means 101 queries, 1000 rows means 1001. Eager loading eliminates this with a single extra JOIN or IN query.

Common Mistakes

  • Accessing a relationship inside a loop without eager loading — ORM lazy-loads on every iteration.
  • Adding with() to the outer query but forgetting nested relationships (with('orders.items') instead of with('orders')).
  • Fixing N+1 in controllers but leaving it in API resources or view composers that loop over collections.
  • Not installing a query debugger (Laravel Debugbar, DBAL logger) — N+1 is invisible without query counting.

Code Examples

✗ Vulnerable
// N+1: 1 query for posts + N queries for author names
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name; // triggers a new query per post
}
✓ Fixed
$posts = Post::with('author')->get(); // 2 queries total
foreach ($posts as $post) {
    echo $post->author->name;
}

Added 13 Mar 2026
Edited 22 Mar 2026
Views 36
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 2 pings S 0 pings S 1 ping M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 2 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S
No pings yet today
No pings yesterday
Perplexity 9 Amazonbot 7 Google 4 Ahrefs 3 Unknown AI 2 SEMrush 1
crawler 26
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Use eager loading (with() in Laravel, addSelect/join in Doctrine) to fetch related data in one query instead of N+1
📦 Applies To
PHP 5.0+ web cli queue-worker laravel doctrine eloquent
🔗 Prerequisites
🔍 Detection Hints
Loop over collection calling ->relation or ->find() per iteration; Laravel Debugbar shows 50+ identical queries
Auto-detectable: ✓ Yes laravel-debugbar clockwork phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update

✓ schema.org compliant