DEV Community

Cover image for The N+1 Query Problem: The Silent Performance Killer
Athreya aka Maneshwar
Athreya aka Maneshwar

Posted on

The N+1 Query Problem: The Silent Performance Killer

Ever heard of a bug that isn’t technically a bug but still ruins your database performance?

Meet the N+1 query problem, the sneaky culprit behind slow applications and overworked servers.

What is the N+1 Query Problem?

Imagine you run a blog platform, and you need to fetch posts along with their comments.

Ideally, you'd want to grab all the data in one go, but your ORM (Object-Relational Mapping) might decide to make separate queries for each post’s comments. This means:

  1. One query fetches all posts.
  2. Then, for each post, an additional query fetches its comments.

If you have 100 posts, that’s 1 + 100 = 101 queries instead of just one. That’s the N+1 query problem!

Why is This Bad?

At first glance, these extra queries may seem harmless since each runs fast. But collectively, they slow things down significantly.

Unlike slow queries that show up in logs, N+1 problems often go unnoticed until response times creep up and your database starts sweating.

A Real-Life Example

Let’s say we have a posts table and a post_comments table:

Sample Data

INSERT INTO post (id, title) VALUES (1, 'Post 1');
INSERT INTO post (id, title) VALUES (2, 'Post 2');
INSERT INTO post_comment (id, post_id, review) VALUES (1, 1, 'Great post!');
INSERT INTO post_comment (id, post_id, review) VALUES (2, 2, 'Very informative.');
Enter fullscreen mode Exit fullscreen mode

The Wrong Way: N+1 Queries in Action

SELECT id, title FROM post;  -- Fetches all posts

SELECT review FROM post_comment WHERE post_id = 1;  -- Fetches comments for post 1
SELECT review FROM post_comment WHERE post_id = 2;  -- Fetches comments for post 2
Enter fullscreen mode Exit fullscreen mode

This triggers one query for posts and one additional query per post for comments. With 100 posts, we’d have 101 queries!

The Right Way: Fixing N+1 with Joins

SELECT p.id, p.title, pc.review FROM post p
JOIN post_comment pc ON p.id = pc.post_id;
Enter fullscreen mode Exit fullscreen mode

Now, we fetch everything in a single query. Much better, right?

How ORMs Make It Worse (and How to Fix It)

Most ORMs like Django ORM, SQLAlchemy, or TypeORM try to make database queries easier, but they often introduce the N+1 problem by default. Here’s how:

The Wrong Way (Lazy Loading)

posts = Post.query.all()  # Fetches all posts
for post in posts:
    print(post.comments)  # Triggers extra queries for each post
Enter fullscreen mode Exit fullscreen mode

Here, the ORM loads comments lazily, triggering a new query for each post. If you have 100 posts, that's 100 additional queries!

The Right Way (Eager Loading)

posts = Post.query.options(joinedload(Post.comments)).all()
Enter fullscreen mode Exit fullscreen mode

Now, the ORM uses a JOIN to fetch everything at once, reducing queries from N+1 to just 1.

Detecting the N+1 Problem

Since N+1 queries don’t always appear in slow query logs, here are some ways to detect them:

  1. Enable query logging – See how many queries are running per request.
  2. Use ORM debugging tools – Many ORMs provide built-in logging to catch excessive queries.
  3. Benchmark response times – Sudden slowdowns in endpoints fetching related data might indicate N+1 issues.

Books and Articles

  • "High Performance MySQL" by Baron Schwartz, Peter Zaitsev, and Vadim Tkachenko: This book provides in-depth knowledge on optimizing MySQL databases, including strategies to avoid common pitfalls like the N+1 query problem.
  • "SQL Performance Explained" by Markus Winand: A comprehensive guide to understanding and improving SQL query performance. It covers various optimization techniques relevant to addressing the N+1 query issue.
  • Articles on PingCAP’s Blog: Explore case studies and technical articles that showcase how the TiDB database has helped organizations overcome performance challenges, including the N+1 query problem.

Final Thoughts

The N+1 problem is a common trap, but once you recognize it, fixing it is easy.

Whether you’re writing raw SQL or using an ORM, always aim for fewer, more efficient queries.

Use joins, eager loading, and profiling tools to keep your database fast and happy.

Next time your app feels sluggish, check if the N+1 problem is lurking behind the scenes!


I’ve been working on a super-convenient tool called LiveAPI.

LiveAPI helps you get all your backend APIs documented in a few minutes

With LiveAPI, you can quickly generate interactive API documentation that allows users to execute APIs directly from the browser.

If you’re tired of manually creating docs for your APIs, this tool might just make your life easier.

Top comments (2)

Collapse
 
ueseatg profile image
1uaef

Can I use this LiveAPI with Flask?

Collapse
 
ganesh-kumar profile image
Ganesh Kumar

Yeah, you can definitely use LiveAPI with Flask.
If you're curious about the setup and more details, take a look at hexmos.com/liveapi/