The N+1 Query Problem is the single most common cause of slow web applications and server crashes in Django. Understanding how to profile queries and apply select_related and prefetch_related turns sluggish, multi-second page loads into sub-10ms responses.
Figure 38.1: Naive ORM Loops vs Single-Query SQL JOINs (select_related) & Batch Lookups (prefetch_related).
Examine this innocent-looking template code rendering a list of 100 blog articles:
# The View:
posts = BlogPost.objects.all()[:100]
return render(request, 'post_list.html', {'posts': posts})
<!-- In the Template: -->
{% for post in posts %}
<h2>{{ post.title }}</h2>
<p>Category: {{ post.category.name }}</p> {# <-- FIRES AN SQL QUERY EVERY ITERATION! #}
<p>Author: {{ post.author.user.username }}</p> {# <-- FIRES ANOTHER QUERY! #}
{% endfor %}
Because category and author were not loaded in the initial query, accessing them inside the loop forces Django to fire 2 extra queries per post. For 100 posts, that is 201 database round-trips for a single page view!
Use select_related() when following single-valued relationships (ForeignKey, OneToOneField):
# Reduced from 201 queries to EXACTLY 1 QUERY via SQL JOIN:
posts = BlogPost.objects.select_related('category', 'author__user')[:100]
For tags (ManyToMany) or comments (reverse ForeignKey), an SQL JOIN would cause a Cartesian product explosion. prefetch_related() executes two fast queries and joins the objects in Python:
from django.db.models import Prefetch
from blog.models import BlogPost, Comment
# Executes exactly 2 SQL queries: 1 for posts, 1 for all approved comments in batch
posts = BlogPost.objects.select_related('category', 'author__user').prefetch_related(
Prefetch('comments', queryset=Comment.objects.filter(is_approved=True).order_by('-created_at'))
)[:50]
Interview Question: "Why does select_related not work on a ManyToManyField?"
Answer: An SQL JOIN across a ManyToMany relationship multiplies rows in the result set (Cartesian explosion), causing duplicate data transfer and severe memory bloat. Django enforces prefetch_related() for multi-valued relations to fetch records in clean batch queries.
Broaden your backend architecture, REST API design, and production engineering expertise:
Understand lazy evaluation and database query execution triggers.
Recognize when relationships cause catastrophic N+1 query loops.
Pair query optimization with caching to achieve sub-10ms response times.
Master the most common senior engineer interview question: N+1 queries.