Skip to main content
eLearner.app
Module 10 · Lesson 4 of 440/57 in the course~12 min
Module lessons (4/4)

The N+1 problem

In backend development, one of the most frequent mistakes that catastrophically tanks API performance is the infamous "N + 1 Queries" problem.

It usually creeps in unknown to the developer who is using library abstractions like "ORMs" (Object-Relational Mappers: e.g. Prisma or Sequelize) to talk to the database from Node.js.

Anatomy of the Disaster

Imagine an app wants to return the entire e-commerce homepage listing: All products together with the string of the category name each one belongs to. Seen from the Node.js side, an inexperienced programmer would write the iterative loop:

  1. products = await db.query("SELECT * FROM products"); (One big, bulky operation 1)
  2. The developer iterates (for..of) over each product in the array of 100 found
  3. On each step, in Node.js they await an iterative sub-query categoryName = await db.query("SELECT name FROM categories WHERE id = " + product.category_id); and embed it into the result (N secondary iterations of slow, tiny queries!)

Total requests to the Postgres daemon: 1 + 100 local iterations = 101 micro network round trips between Node.js and the DB. 101 round trips cause horrendous network overhead and ugly latency. At real scale, N might not be 100 but 10,000 rows of total invoices to explore! The API wouldn't return before hitting a 5xx timeout.

The Real Native Answer: JOIN or Aggregation in a Single Query

Masterfully using DBMS abstractions written by hand, instead of trivial ORM commands in Node, fuses the executions together in milliseconds in a single, unbeatable query that solves the "N+1" mess:

SQL
SELECT
  p.id,
  p.name,
  c.name AS category_name
FROM products p
JOIN categories c ON p.category_id = c.id;

Total API/DB round trips: 1 unique query, fused, mathematically optimized by Postgres's own indexes, handled entirely with 0 milliseconds of extra network latency.

JSON aggregation alternative

Modern Postgres versions even let you return the entire complex join nested as JSON with json_agg, allowing your JavaScript to receive the products array including their sub-array of formatted reviews without any local script glue! (In the advanced paths and challenges you'll study Postgres's JSONb clause.)

Your turn

Exercise#sql.m10.l4.e1
Attempts: 0Loading…

Let's solve a real N+1 Problem in the making.\nNode would have run a global Select and then iterated over every customer to find their names if it wanted a recap of orders shipped this morning.\nSolve it by printing me in a single native shot a JOIN between 'customers' (use the original textual alias 'c') and 'orders' (alias 'o').\nExtract 2 trivial fields (forcing formal alias prefixing): 'c.first_name' (from the customer) and 'o.status' (from the pending order).

Loading editor…
Show hint

Syntax: SELECT c.first_name, o.status FROM customers c JOIN orders o ON c.id = o.customer_id;

Solution available after 3 attempts

Exploring GROUP BY efficiency

Exercise#sql.m10.l4.e2
Attempts: 0Loading…

If logical Group-Bys aren't used inside the database to get the total count per row and category, Node.js would call the DB endlessly, blowing up into N+1.\nWrite a single query that selects the 'city' field from 'customers' and the standard Postgres count 'COUNT(id)' using the terminal keyword to aggregate them uniquely by name.

Loading editor…
Show hint

A trivial: SELECT city, COUNT(id) FROM customers GROUP BY city;

Solution available after 3 attempts