Saltar al contenido principal
eLearner.app
Módulo 10 · Lección 4 de 440/57 en el curso~12 min
Lecciones del módulo (4/4)

El problema N+1

En el desarrollo backend, uno de los errores más frecuentes que afecta catastróficamente el rendimiento de la API es el infame problema "N + 1 consultas".

Por lo general, resulta desconocido para el desarrollador que utiliza abstracciones de biblioteca como "ORM" (Mapeadores relacionales de objetos: por ejemplo, Prisma o Sequelize) para comunicarse con la base de datos desde Node.js.

Anatomía del desastre

Imagine que una aplicación quiere devolver el listado completo de la página de inicio del comercio electrónico: Todos los productos junto con la cadena del nombre de la categoría a la que pertenece cada uno. Visto desde el lado de Node.js, un programador sin experiencia escribiría el bucle iterativo:

  1. products = await db.query("SELECT * FROM products"); (Una operación grande y voluminosa 1)
  2. El desarrollador itera (for..of) sobre cada product en la matriz de 100 encontrada
  3. En cada paso, en Node.js esperan una subconsulta iterativa categoryName = await db.query("SELECT name FROM categories WHERE id = " + product.category_id); y la incrustan en el resultado (¡N iteraciones secundarias de consultas pequeñas y lentas!)

Solicitudes totales al demonio de Postgres: 1 + 100 iteraciones locales = 101 viajes de ida y vuelta de microred entre Node.js y la base de datos. 101 viajes de ida y vuelta provocan una sobrecarga de red horrenda y una latencia desagradable. ¡A escala real, N podría no ser 100 sino 10,000 filas de facturas totales para explorar! La API no regresaría antes de alcanzar un tiempo de espera de 5xx.

La verdadera respuesta nativa: ÚNETE o agregación en una sola consulta

El uso magistral de abstracciones DBMS escritas a mano, en lugar de comandos ORM triviales en Node, fusiona las ejecuciones en milisegundos en una consulta única e inmejorable que resuelve el desorden "N+1":

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

Total de viajes de ida y vuelta de API/DB: 1 consulta única, fusionada, optimizada matemáticamente por los propios índices de Postgres, manejada en su totalidad con 0 milisegundos de latencia de red adicional.

Alternativa de agregación JSON

Las versiones modernas de Postgres incluso le permiten devolver toda la combinación compleja anidada como JSON con json_agg, lo que permite que su JavaScript reciba la matriz products, incluida su submatriz de revisiones formateadas, ¡sin ningún pegamento de script local! (En las rutas y desafíos avanzados estudiará la cláusula JSONb de Postgres).

Tu turno

Ejercicio#sql.m10.l4.e1
Intentos: 0Cargando...

Resolvamos un problema real de N+1 en ciernes. Node habría ejecutado una selección global y luego habría iterado sobre cada cliente para encontrar sus nombres si quisiera un resumen de los pedidos enviados esta mañana. Resuélvelo imprimiendo en una sola toma nativa un JOIN entre 'clientes' (use el alias textual original 'c') y 'pedidos' (alias 'o'). Extraiga 2 campos triviales (forzando el prefijo de alias formal): 'c.first_name' (del cliente) y 'o.status' (del pedido pendiente).

Cargando editor...
Mostrar pista

Sintaxis: SELECCIONAR c.first_name, o.status FROM clientes c UNIR pedidos o ON c.id = o.customer_id;

Solución disponible después de 3 intentos

Explorando la eficiencia GRUPO POR

Ejercicio#sql.m10.l4.e2
Intentos: 0Cargando...

Si no se utilizan Group-Bys lógicos dentro de la base de datos para obtener el recuento total por fila y categoría, Node.js llamaría a la base de datos sin cesar, expandiéndose a N+1. Escriba una única consulta que seleccione el campo 'ciudad' de 'clientes' y el recuento estándar de Postgres 'COUNT(id)' usando la palabra clave terminal para agregarlos de forma única por nombre.

Cargando editor...
Mostrar pista

Un trivial: SELECCIONAR ciudad, CONTAR (id) DE clientes GRUPO POR ciudad;

Solución disponible después de 3 intentos