{
    "slug": "n_plus_one_orm",
    "term": "N+1 Problem in Doctrine & Eloquent",
    "category": "performance",
    "difficulty": "intermediate",
    "short": "Accidentally issuing one query per related entity instead of one JOIN — the most common ORM performance pitfall, solved by eager loading.",
    "long": "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.",
    "aliases": [
        "ORM N+1",
        "Eloquent N+1",
        "lazy load N+1 ORM"
    ],
    "tags": [
        "performance",
        "orm",
        "database",
        "php"
    ],
    "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."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "eager_loading",
        "eager_vs_lazy_loading",
        "query_optimisation",
        "orm"
    ],
    "prerequisites": [
        "n_plus_one",
        "eager_loading",
        "db_n_plus_one"
    ],
    "refs": [
        "https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/dql-doctrine-query-language.html#joins"
    ],
    "bad_code": "$orders = $em->findAll(Order::class); // 1 query\nforeach ($orders as $o) {\n    echo $o->getCustomer()->getName(); // N queries!\n}",
    "good_code": "$orders = $em->createQuery(\n    'SELECT o, c FROM Order o JOIN FETCH o.customer c'\n)->getResult(); // 1 query",
    "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",
    "severity": "high",
    "effort": "low",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/n_plus_one_orm",
        "html_url": "https://codeclaritylab.com/glossary/n_plus_one_orm",
        "json_url": "https://codeclaritylab.com/glossary/n_plus_one_orm.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[N+1 Problem in Doctrine & Eloquent](https://codeclaritylab.com/glossary/n_plus_one_orm) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/n_plus_one_orm"
            }
        }
    }
}