Software Architecture Styles

N+1 Problem

The N+1 problem is when fetching a list of N items then fetching related data for each one results in 1 + N queries. One query for the list. N more queries to hydrate each item. From ECE459 L10.

Why?

It feels natural to write a loop: “get the list, then for each item, get its details.” That loop turns into a round-trip per item. Latency adds up on the wire, not in the code you see.

The L10 example

You want to email every customer with an unpaid invoice:

  1. Query 1: get customer IDs for all unpaid invoices
  2. For each of 500 invoices, query the customer’s email

Result: 501 queries when 1 or 2 would do.

Fixes:

  • Single join query that returns emails directly
  • WHERE customer_id IN (...) — down to 2 queries
  • Eager loading: fetch related entities alongside the originals, even if you might not need them

Where it hides

  • ORMs (Hibernate, Rails ActiveRecord) silently turn nested object access into separate queries. A .author.name in a loop is N extra SELECTs
  • GraphQL resolvers let the caller pick arbitrary nested fields. The resolver often fires one query per parent row unless you batch
  • REST endpoints that return thin objects and force the client to fan out

In practice. The Rust juniper_eager_loading crate models this explicitly with a HasOne<T> enum (Loaded / NotLoaded). You load users first, collect their country IDs, fetch those countries in one query, then stitch them back. Two queries instead of N+1.

Reference: The GraphQL DataLoader pattern visualized