Lekcje modułu (4/4)
Problem N+1
Podczas tworzenia backendu jednym z najczęstszych błędów, który katastrofalnie obniża wydajność API, jest niesławny problem „N + 1 zapytań”.
Zwykle wkrada się w sposób nieznany programiście, który używa abstrakcji bibliotecznych, takich jak „ORM” (mapery obiektowo-relacyjne: np. Prisma lub Sequelize), aby komunikować się z bazą danych z Node.js.
Anatomia katastrofy
Wyobraź sobie, że aplikacja chce zwrócić całą listę stron głównych e-commerce: Wszystkie produkty wraz z ciągiem nazwy kategorii, do której każdy należy. Patrząc od strony Node.js, niedoświadczony programista napisałby pętlę iteracyjną:
products = await db.query("SELECT * FROM products");(Jedna duża, nieporęczna operacja 1)- Programista wykonuje iterację (
for..of) po każdymproductw tablicy 100 znalezionych - Na każdym kroku w Node.js czekają na iteracyjne podzapytanie
categoryName = await db.query("SELECT name FROM categories WHERE id = " + product.category_id);i osadzają je w wyniku (N wtórnych iteracji powolnych, drobnych zapytań!)
Łączna liczba żądań do demona Postgres: 1 + 100 iteracji lokalnych = 101 podróży w obie strony w mikrosieci między Node.js a bazą danych. 101 podróży w obie strony powoduje straszliwe obciążenie sieci i brzydkie opóźnienia. W rzeczywistej skali N może nie wynosić 100, ale 10 000 wierszy wszystkich faktur do zbadania! Interfejs API nie powróciłby przed osiągnięciem limitu czasu 5xx.
Prawdziwa odpowiedź natywna: DOŁĄCZ lub agregacja w jednym zapytaniu
Mistrzowskie wykorzystanie abstrakcji DBMS napisanych ręcznie, zamiast trywialnych poleceń ORM w Node, łączy wykonania w ciągu milisekund w jednym, bezkonkurencyjnym zapytaniu, które rozwiązuje bałagan „N+1”:
SELECT
p.id,
p.name,
c.name AS category_name
FROM products p
JOIN categories c ON p.category_id = c.id;Całkowita liczba cykli API/DB: 1 unikalne zapytanie, połączone, zoptymalizowane matematycznie przez własne indeksy Postgres, obsługiwane w całości z dodatkowym opóźnieniem sieci wynoszącym 0 milisekund.
Alternatywa agregacji JSON
Nowoczesne wersje Postgres pozwalają nawet zwrócić całe złożone sprzężenie zagnieżdżone jako JSON z json_agg, dzięki czemu Twój JavaScript może otrzymać tablicę products, w tym podtablicę sformatowanych recenzji, bez żadnego lokalnego kleju skryptowego! (W zaawansowanych ścieżkach i wyzwaniach będziesz studiować klauzulę JSONb Postgresa.)
Twoja kolej
Rozwiążmy prawdziwy problem N+1 w trakcie tworzenia. Węzeł uruchomiłby globalny wybór, a następnie iterował po każdym kliencie, aby znaleźć jego nazwiska, gdyby chciał podsumowania zamówień wysłanych dziś rano. Rozwiąż go, drukując mi w jednym natywnym ujęciu JOIN pomiędzy „klientami” (użyj oryginalnego aliasu tekstowego „c”) i „zamówieniami” (aliasem „o”). Wyodrębnij 2 trywialne pola (wymuszając formalny alias) przedrostek): 'c.first_name' (od klienta) i 'o.status' (od oczekującego zamówienia).
Pokaż wskazówkę
Składnia: SELECT c.imię_pierwszego, o.status FROM klientów c DOŁĄCZ zamówienia o ON c.id = o.id_klienta;
Rozwiązanie dostępne po 3 próbach
Odkrywanie wydajności GROUP BY
Jeśli w bazie danych nie zostaną użyte logiczne metody grupowania w celu uzyskania całkowitej liczby wierszy i kategorii, Node.js będzie wywoływał bazę danych w nieskończoność, zwiększając liczbę N+1. Napisz pojedyncze zapytanie, które wybierze pole „miasto” z pola „klienci” i standardową liczbę Postgres „COUNT(id)”, używając słowa kluczowego terminal, aby agregować je jednoznacznie według nazwy.
Pokaż wskazówkę
Banalne: WYBIERZ miasto, COUNT(id) OD klientów GROUP BY miasto;
Rozwiązanie dostępne po 3 próbach