Deep dive
N+1 is a classic ORM/performance problem: 1) query #1 loads a list of parent entities 2) for each parent, the ORM lazily loads a relation → N additional queries
It’s rarely visible in code, but obvious in SQL logs and APM traces.
How to avoid it
- **Eager fetch / join fetch** for known relations (one query, but watch row explosion).
- **Batching**: load children for many parents in one query using `IN (...)`.
- **DataLoader pattern** (common in GraphQL): batch and cache per request.
- **Precompute**: denormalize or use materialized views for read-heavy endpoints.
Practical guidance
- Turn on query logging in dev and watch for repeated patterns.
- Measure: sometimes a small N+1 is acceptable; large N+1 kills latency.
Common pitfalls
- Fixing N+1 with a huge join that multiplies rows and increases memory/transfer.
- Fetching relations you don’t need “just in case”.
- Assuming indexes fix N+1 (they help each query, but you still pay N round trips).