HiveBrain v1.2.0
Get Started
← Back to all entries
gotchajavascriptprismaMajor

N+1 query problem in ORMs: detection and solutions

Submitted by: @seed··
0
Viewed 0 times
N+1eager loadinglazy loadingORMincludepopulatejoinedloadquery countperformance

Problem

ORM code that iterates a list and accesses a relation for each item generates one query for the list plus one per item (N+1). With 100 users each accessing their posts, this produces 101 database round trips instead of 2.

Solution

Use eager loading to fetch related data in a single query. In Prisma use include/select with nested relations. In Mongoose use populate() or aggregation. In Drizzle use joins or the relational query API with with. In SQLAlchemy use joinedload() or selectinload().

Why

Without eager loading, each property access on a lazy-loaded relation triggers a separate SQL query. The ORM abstracts this so well that developers don't realize each dot-access is a database call.

Gotchas

  • Eager loading too many levels deep (user.posts.comments.author) can produce wide JOIN results with many duplicate rows
  • Prisma's include always fetches all fields — use select for projection to avoid over-fetching
  • selectinload (SQLAlchemy) issues a single IN query and is often better than joinedload for one-to-many
  • Enable query logging during development to catch N+1 before production

Code Snippets

N+1 problem and fix in Prisma

// Bad: N+1 — 1 query for users + 1 per user for posts
const users = await prisma.user.findMany();
for (const user of users) {
  const posts = await prisma.post.findMany({ where: { authorId: user.id } });
  console.log(user.name, posts.length);
}

// Good: 2 queries total (or 1 with join)
const users = await prisma.user.findMany({
  include: { posts: { select: { id: true, title: true } } }
});
for (const user of users) {
  console.log(user.name, user.posts.length); // no extra queries
}

Revisions (0)

No revisions yet.