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:
products = await db.query("SELECT * FROM products");(Una operación grande y voluminosa 1)- El desarrollador itera (
for..of) sobre cadaproducten la matriz de 100 encontrada - 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":
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
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).
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
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.
Mostrar pista
Un trivial: SELECCIONAR ciudad, CONTAR (id) DE clientes GRUPO POR ciudad;
Solución disponible después de 3 intentos