Wie eine fehlende Spalte unsere Datenbank lahmgelegt hat
Ein einziger fehlender Index verwandelte eine 8-ms-API in einen 8-Sekunden-Albtraum.
Wir haben vor einem großen Release einen Lasttest durchgeführt. In der lokalen Entwicklung liefen 100 Zeilen problemlos. In der Staging-Umgebung simulierten wir 500 Nutzer gegen 1,5 Millionen Zeilen.
Alles brach zusammen.
- Die API-Antwortzeiten sprangen von 45 ms auf 8.000 ms.
- Die Datenbank-CPU erreichte 100 %.
- Die Connection Pools waren erschöpft.
- Anfragen liefen in ein Timeout.
Der Übeltäter war eine einfache Abfrage, die die Bestellhistorie nach user_id und status abfragte.
Die Ausführung von EXPLAIN ANALYZE auf PostgreSQL zeigte einen Sequential Scan. Da kein Index auf user_id vorhanden war, las die Engine bei jeder Anfrage alle 1,5 Millionen Zeilen.
Bei 100 gleichzeitigen Anfragen scannte die Datenbank 150 Millionen Zeilen auf einmal.
Die Behebung dauerte fünf Minuten. Wir erstellten einen zusammengesetzten Index auf (user_id, status, created_at DESC) mit CREATE INDEX CONCURRENTLY, damit die Tabelle online blieb.
Ergebnisse:
- Die Abfragezeit sank von 8.150 ms auf 0,14 ms.
- Die API-Latenz sank von 8 Sekunden auf 12 ms.
- Die CPU-Auslastung fiel von 100 % auf unter 8 %.
Gelernte Lektionen:
- Lokale Tests täuschen; 100 Zeilen sind kein Indikator für eine Million.
- Indizieren Sie Fremdschlüssel – die meisten ORMs lassen dies aus.
- Nutzen Sie
EXPLAIN ANALYZE; die Datenbank zeigt das Problem auf. - Optimieren Sie Abfragen, bevor Sie mehr Hardware kaufen.
Skalieren Sie nicht zuerst die Server. Skalieren Sie die Abfragen.
