What is the N+1 Query Problem?
The N+1 query problem is one of the most common performance issues in web applications.
Imagine you want to display a list of blog posts with each author's name:
# Bad example (Django ORM)
posts = Post.objects.all() # 1 query
for post in posts:
print(post.author.name) # 1 query per post -> N queries
If there are 100 posts, this executes 101 SQL queries. That's the N+1 problem.
Finding Candidates with grep
Before using Claude Code, scan the entire codebase for N+1 candidates.
# Detect loop-based access patterns in Django
grep -rn "for.*in.*\.objects\." src/
grep -rn "\.objects\.get\|\.objects\.filter" src/ | grep -v "select_related\|prefetch_related"
# N+1 patterns in Express.js + Sequelize
grep -rn "findOne\|findAll" src/ | grep -v "include:"
This gives you a list of suspicious spots. Feed them to Claude Code next.
Using Claude Code to Detect and Fix
Run the following at your project root:
claude "Detect all N+1 queries in this code and suggest fixes.
Target: src/views/posts.py
Format: line number, current code, fixed code"
Django: select_related / prefetch_related
# Fixed (ForeignKey: select_related)
posts = Post.objects.select_related('author').all()
for post in posts:
print(post.author.name) # 1 query with JOIN
# Fixed (ManyToMany / reverse: prefetch_related)
posts = Post.objects.prefetch_related('tags').all()
for post in posts:
print([tag.name for tag in post.tags.all()]) # 2 queries with IN clause
Verify the query count with:
from django.db import connection
posts = Post.objects.all()
for post in posts:
_ = post.author.name
print(len(connection.queries)) # Before fix: 101
Express.js + Sequelize
// Bad
const posts = await Post.findAll();
for (const post of posts) {
post.author = await User.findByPk(post.authorId); // N queries
}
// Fixed (Eager loading)
const posts = await Post.findAll({
include: [{ model: User, as: 'author', attributes: ['name', 'email'] }]
});
Rails (ActiveRecord)
# Bad
Post.all.each { |p| puts p.author.name }
# Fixed
Post.includes(:author).each { |p| puts p.author.name }
Automate with the /code-review Skill
Checking manually every time is inefficient. With Claude Code's /code-review skill, you can automate this on every PR.
# Configure in .claude/commands/code-review.md
claude /code-review src/
Example skill config (.claude/commands/code-review.md):
Perform a code review with the following rules.
## Checklist
1. Detect N+1 queries (DB calls inside loops)
2. WHERE clauses without indexes
3. Unused variables / imports
## Output Format
- filename:line_number
- Description of the issue
- Fixed code snippet
This automatically detects N+1 queries before every commit.
Benchmark: Before vs After
Results from a real Django project:
| Condition | Query Count | Response Time |
|---|---|---|
| Before fix (100 posts) | 101 | 450ms |
| After select_related | 2 | 28ms |
| Improvement | -98% | 16x faster |
N+1 fixes are zero-cost changes that deliver the biggest performance gains — always tackle these first.
Summary
- Use
grepto find DB calls inside loops - Use Claude Code to identify issues and generate fixes
- Automate with the
/code-reviewskill on every PR - Django:
select_related/prefetch_related; Sequelize:include:
N+1 queries are easy to miss but simple to fix. With AI, you can scan large codebases in minutes.
Code Review Pack — A 3-skill set:
/code-review,/test-gen,/refactor. N+1 detection is included.
Top comments (0)