python / intermediate
Snippet
Django QuerySet-Optimierung mit select_related und prefetch_related
Das N+1-Abfrageproblem von Django tritt auf, wenn auf verknüpfte Objekte in Schleifen zugegriffen wird, was eine Abfrage pro Iteration erzeugt. select_related führt SQL-Joins für ForeignKey- und OneToOne-Beziehungen aus und holt verknüpfte Daten in einer einzigen Abfrage. prefetch_related ist für Reverse-ForeignKey- und ManyToMany-Beziehungen optimiert und führt eine separate Abfrage aus.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from django.db.models import Prefetchfrom .models import Author, Article, Tag# N+1 problem example - inefficientauthors = Author.objects.all()for author in authors:print(author.articles.all().count()) # New query for each author# Solution 1: select_related for ForeignKey/OneToOneauthors_optimized = Author.objects.select_related('profile').all()# Solution 2: prefetch_related for reverse ForeignKey/ManyToManyarticles = Article.objects.prefetch_related(Prefetch('tags', queryset=Tag.objects.filter(is_active=True))).all()# Solution 3: Combined optimal queryauthors_best = Author.objects.select_related('profile').prefetch_related('articles__tags').all()# Debug query countfrom django.db import connectionprint(f"Queries executed: {len(connection.queries)}")
django
Erklärung
1
from django.db.models import Prefetch
Importiere Prefetch um die Queryset für vorabgerufene Beziehungen anzupassen
2
for author in authors:
Durchlaufen der Autoren verursacht N+1-Problem - eine Abfrage pro Autor für Artikel
3
select_related('profile')
Verwendet SQL-JOIN um Profildaten in derselben Abfrage für ForeignKey-Beziehung zu holen
4
Prefetch('tags', queryset=Tag.objects.filter(is_active=True))
Prefetch mit benutzerdefinierter Queryset filtert Tags vor dem Join, reduziert Datentransfer
5
'articles__tags'
Verschachteltes Prefetch durchläuft Beziehungen: Artikel dann deren Tags in optimierten Abfragen
6
from django.db import connection
Importiere Verbindung um auf Abfrage-Logs zuzugreifen und Performance zu überwachen
7
len(connection.queries)
Prüfe Anzahl der SQL-Abfragen um die Optimierung zu verifizieren