1.8 KiB
1.8 KiB
ANTI-PATTERN: N+1 Queries in Django ORM
KONTEXT
Django/DRF API-Entwicklung, insbesondere bei Listen-Endpoints mit Related Objects.
WAS IST PASSIERT?
# SCHLECHT: N+1 Query Problem
def get_matches(request):
matches = Match.objects.filter(scenario_id=scenario_id)
return Response([{
'id': m.id,
'home_team': m.home_team.name, # Query für jedes Match!
'away_team': m.away_team.name, # Noch eine Query!
'venue': m.home_team.venue.name # Und noch eine!
} for m in matches])
Bei 100 Matches: 1 + 100 + 100 + 100 = 301 Queries statt 1-4.
WARUM WAR ES SCHLECHT?
- Performance: Exponentieller Anstieg der DB-Queries mit Datenmenge
- Latenz: Jede Query hat Overhead (Netzwerk, Parsing, Locking)
- DB-Last: Unnötige Belastung der Datenbank
- Skalierung: Funktioniert in Dev (10 Records), bricht in Prod (10.000 Records)
DIE BESSERE ALTERNATIVE
# GUT: Optimierte Queries
def get_matches(request):
matches = Match.objects.filter(
scenario_id=scenario_id
).select_related(
'home_team',
'away_team',
'home_team__venue', # Nested relation
)
return Response([{
'id': m.id,
'home_team': m.home_team.name,
'away_team': m.away_team.name,
'venue': m.home_team.venue.name
} for m in matches])
Bei 100 Matches: 1 Query (mit JOINs).
ERKENNUNGSREGELN
select_related()für ForeignKey / OneToOneFieldprefetch_related()für ManyToMany / Reverse ForeignKey- Django Debug Toolbar zeigt Query-Anzahl
django-query-counterals Middleware
CHECKLISTE
- Hat jeder Listen-Endpoint
select_related/prefetch_related? - Werden verschachtelte Relations berücksichtigt?
- Ist die Query-Anzahl bei >100 Records akzeptabel?