An N+1 query problem occurs when an application fetches a collection of records, then makes another database query for related data for each record. The fix is usually to load the needed relation in a join or a batch—but first confirm the repeated queries are the source of the slowdown.
What is the N+1 query problem?
Suppose a page loads N pizzas with one query. While rendering the page, it then loads toppings separately for each pizza. The result is one query for the collection plus N more queries for related data: the pattern’s “1” and “N.” It can be hard to spot because the extra work may be triggered by ordinary-looking property access rather than an explicit query in the loop.
As an Amazon Associate I earn from qualifying purchases.
In Django’s documented example, evaluating each pizza’s string representation accesses its toppings. Calling Pizza.objects.all() therefore appears simple, but the related-data access can produce a query per pizza. Using prefetch_related("toppings") makes this specific example two queries: one for pizzas and one batched lookup for toppings. That is a documented example, not a universal query-count guarantee. Django QuerySet API reference
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsThe performance cost is repeated database round trips and the work they trigger, not the number of queries in isolation. Round trips can add latency, particularly when the application and database communicate over a network. A high query count is a useful clue, but it does not by itself establish which endpoint is slow or which change will help.
#1 Best Overall
Where can the extra queries be hiding?
Look beyond explicit database calls. Lazy loading means related data may be fetched only when code first accesses it, so the query can originate somewhere unexpected.
- Loops in application code: each iteration accesses a related object or collection.
- Templates: a template displays a relation for every item in a result set.
- Model methods or string conversion: a method used during rendering accesses related data.
- Serializers: converting model objects to API output traverses relations. Django REST Framework says it does not automatically optimize serializer querysets; its documentation demonstrates prefetching tracks when serializing albums. Django REST Framework: Serializer relations
Which Django fix fits the relationship?
For Django, choose the loading method based on the relation and the data the code actually needs. These API names and behaviors are Django-specific; other frameworks require their own documentation and conventions.
Rank #2
| Approach | Best fit | How it fetches related data | Trade-off |
|---|---|---|---|
select_related() |
Foreign-key or one-to-one relation | Joins related data into the main SQL query | Creates a more complex query and may return more data |
prefetch_related() |
Many-to-many or other many-valued relation | Runs a separate batch lookup, then associates results in Python | Uses memory for loaded results; query count depends on relationship depth and type |
Use select_related() for a single related object
When each record points to one related object through a foreign key or one-to-one relation, select_related() uses a SQL join to populate that object alongside the main result. Django describes it as “a performance booster, fetching data ahead of time rather than triggering on-demand loading through the model instances’ fetch mode, at the cost of a more complex initial query.” Django QuerySet API reference
Use prefetch_related() for collections
For a collection such as toppings on pizzas, prefetch_related() fetches related rows in a separate batch query and matches them to their parent objects in Python. This can replace per-record lookups with a bounded number of queries, but the precise count depends on the relationship path and type.
Combine the methods for mixed paths
A relation path can include both a single object and a collection. Django documents combining select_related("best_pizza") with prefetch_related("best_pizza__toppings"): the single-valued pizza is joined to the restaurant query, and the toppings are fetched in a batch. Django QuerySet API reference
How do you diagnose and verify an N+1?
- Reproduce the slow operation with representative data. Inspect its SQL or query log. Look for a repeated query whose structure stays the same while a bound identifier changes from one parent record to another.
- Trace the relation access. Check loops, templates, model methods, string conversion, serializers, and resolvers for the access that triggers lazy loading.
- Optimize the specific access path. In Django, use
select_related()for a single-valued relation orprefetch_related()for a collection. Fetch only the relation and subset the code will use. - Run the same operation again. Inspect the generated SQL and execution plan. Django provides
QuerySet.explain()for details such as joins and indexes, and query inspection throughdjango.db.connection.queries. Django database optimization guide - Compare actual performance and resource use. Check elapsed time and the work the database performs, not only query count. A lower count can still be worse if it loads excess rows, consumes too much memory, or produces an unfavorable plan.
When can eager loading make things worse?
Loading related data up front is not automatically beneficial. A broad prefetch can consume substantial memory, and large result sets can produce a large SQL IN clause. A later filtered access to a relation may issue a new query instead of using the prefetched cache. Also, the main query and prefetch queries run separately; concurrent changes between them can affect which related rows the application observes. Django QuerySet API reference
Rank #4
Keep the optimization narrow: fetch the relation and data the code will use, then measure the same operation with realistic data. Django’s optimization guidance recommends inspecting the actual SQL and execution details rather than assuming that fewer queries alone means faster execution. Django database optimization guide
Recommended Free Tools
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




