Salt la conținutul principal
Modulul 10 · Lecția 4 din 440/57 în curs~12 min
Lecții din modul (4/4)

Problema N+1

În dezvoltarea backend, una dintre cele mai frecvente greșeli care limitează catastrofal performanța API este infama problemă „N + 1 Queries”.

De obicei, se strecoară în necunoscut dezvoltatorului care utilizează abstracții de bibliotecă, cum ar fi „ORM-uri” (Object-Relational Mappers: de exemplu, Prisma sau Sequelize) pentru a vorbi cu baza de date din Node.js.

Anatomia dezastrului

Imaginați-vă că o aplicație dorește să returneze întreaga pagină de pornire a comerțului electronic: Toate produsele împreună cu șirul numelui categoriei din care aparține fiecare. Văzut din partea Node.js, un programator fără experiență ar scrie bucla iterativă:

  1. products = await db.query("SELECT * FROM products"); (O operațiune mare și voluminoasă 1)
  2. Dezvoltatorul iterează (for..of) peste fiecare product din matricea de 100 găsite
  3. La fiecare pas, în Node.js ei așteaptă o sub-interogare iterativă categoryName = await db.query("SELECT name FROM categories WHERE id = " + product.category_id); și o încorporează în rezultat (N iterații secundare de interogări lente, mici!)

Total de solicitări către demonul Postgres: 1 + 100 de iterații locale = 101 călătorii dus-întors în microrețea între Node.js și DB. 101 călătorii dus-întors provoacă o supraîncărcare îngrozitoare a rețelei și o latență urâtă. La scară reală, N ar putea să nu fie 100, ci 10.000 de rânduri de facturi totale de explorat! API-ul nu va reveni înainte de a atinge un timeout 5xx.

Răspunsul nativ real: JOIN sau agregare într-o singură interogare

Folosind cu măiestrie abstracțiile DBMS scrise de mână, în loc de comenzi ORM banale în Node, fuzionează execuțiile împreună în milisecunde într-o singură interogare imbatabilă care rezolvă mizeria „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 călătorii dus-întors API/DB: 1 interogare unică, fuzionată, optimizată matematic de proprii indexuri Postgres, gestionată în întregime cu 0 milisecunde de latență suplimentară a rețelei.

Alternativă de agregare JSON

Versiunile moderne Postgres vă permit chiar să returnați întreaga unire complexă imbricată ca JSON cu json_agg, permițând JavaScript-ului dvs. să primească matricea products, inclusiv sub-matricea lor de recenzii formatate, fără adeziv script local! (În căile și provocările avansate veți studia clauza JSONb a Postgres.)

Rândul tău

Exercițiu#sql.m10.l4.e1
Încercări: 0Se încarcă…

Să rezolvăm o adevărată problemă N+1 în curs.\nNode ar fi rulat o selecție globală și apoi ar fi repetat peste fiecare client pentru a-și găsi numele dacă ar fi vrut o recapitulare a comenzilor expediate în această dimineață.\nRezolvați-o prin imprimarea într-o singură fotografie nativă a JOIN între „clienți” (folosește aliasul textual original „c”) și câmpul „comenzi extrase” (câmpul „extras2”). (forțând prefixarea aliasului formal): „c.first_name” (de la client) și „o.status” (din comanda în așteptare).

Se încarcă editorul...
Afișează indiciu

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

Soluție disponibilă după 3 încercări

Explorarea eficienței GROUP BY

Exercițiu#sql.m10.l4.e2
Încercări: 0Se încarcă…

Dacă Group-By-urile logice nu sunt utilizate în baza de date pentru a obține numărul total pe rând și categorie, Node.js va apela DB la nesfârșit, explodând în N+1.\nScrieți o singură interogare care selectează câmpul „oraș” din „clienți” și standardul Postgres numără „COUNT(id)” folosind cuvântul cheie terminal pentru a le agrega unic după nume.

Se încarcă editorul...
Afișează indiciu

Un banal: SELECT oraș, COUNT(id) FROM clienți GROUP BY oraș;

Soluție disponibilă după 3 încercări