Waarom wordt het N+1 probleem in Django ORM zo vaak genoemd?
Wanneer je Django ORM gebruikt, kom je vaak de term "N+1 probleem" tegen. Maar zonder het zelf te ervaren, is het moeilijk te begrijpen hoe ernstig dit probleem kan zijn.
In eenvoudige bewoordingen is het een probleem waarbij "een query die slechts één keer zou moeten worden uitgevoerd, veel vaker wordt uitgevoerd dan verwacht". Als gevolg hiervan kan de laadsnelheid van de pagina aanzienlijk vertragen, en naarmate er meer gegevens zijn, verergert de prestatie nog verder. Dit probleem doet zich vooral voor bij het ophalen van gegevens met relaties tussen modellen, daarom is het essentieel om dit te begrijpen wanneer je ORM gebruikt.
💡 Laten we het N+1 probleem eenvoudig begrijpen
Laten we zeggen dat we een blogsysteem maken. Elke Auteur kan meerdere Berichten schrijven. Als we dit in Django-modellen zouden uitdrukken, zou het er als volgt uitzien.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Post(models.Model):
title = models.CharField(max_length=255)
content = models.TextField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
Aangezien elke Auteur meerdere Berichten kan schrijven, betreft dit een 1:N relatie.
Laten we nu aannemen dat we een functie willen implementeren die de namen van alle auteurs en de titels van de berichten die zij hebben geschreven weergeeft. In de praktijk zou je het waarschijnlijk als volgt schrijven.
⚠️ Code waarbij het N+1 probleem optreedt
authors = Author.objects.all() # (1) Eerste query (ophalen van auteurs)
for author in authors:
print(author.post_set.all()) # (N) Elk bericht van de auteur apart opvragen
Na een enkele uitvoering kan het langer duren om te laden dan verwacht. Als er weinig gegevens zijn, kan het niet opvallen, maar wat als er 100 auteurs zijn en meer dan 500 berichten? Dan beginnen de problemen duidelijk te worden.
🧐 Eigenlijk uitgevoerde SQL-query
SELECT * FROM author; -- 1 keer uitgevoerd
SELECT * FROM post WHERE author_id = 1; -- N keer uitgevoerd
SELECT * FROM post WHERE author_id = 2;
SELECT * FROM post WHERE author_id = 3;
...
Zoals je ziet, nemen het aantal queries exponentieel toe naarmate er meer auteurs zijn. Dit is het N+1 probleem.
🚀 In welke situaties komt het N+1 probleem vaak voor?
Dit probleem moet bijna altijd in de gaten gehouden worden, ongeacht of je Django ORM goed of slecht gebruikt als je twee of meer modellen met gerelateerde gegevens ophaalt. Het komt vaak voor in de volgende situaties.
1️⃣ Wanneer je in een loop in een sjabloon gegevens raadpleegt
{% for author in authors %}
{{ author.name }}
{% for post in author.post_set.all %}
- {{ post.title }}
{% endfor %}
{% endfor %}
Wanneer je in een sjabloon een loop maakt om toegang te krijgen tot gegevens, worden er extra queries uitgevoerd voor elk object, wat de prestaties verzwakt.
2️⃣ Wanneer je in een loop in een view functie gerelateerde modellen raadpleegt
def blog_view(request):
authors = Author.objects.all() # Eerste query (ophalen auteurs)
author_list = []
for author in authors:
author_list.append({
'name': author.name,
'posts': author.post_set.all() # N extra queries
})
return render(request, 'blog.html', {'authors': author_list})
Hetzelfde probleem kan ook optreden wanneer je gegevens in een view functie verwerkt.
💡 Mijn ervaring met het N+1 probleem
Vroeger heb ik een aangepaste methode gemaakt genaamd get_absolute_url()
.
Het was een functie die een URL genereerde door meerdere velden van een model te combineren, en pas na te hebben ervaren dat de prestaties traag waren, vond ik de oorzaak.
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def get_absolute_url(self):
return f"/author/{self.author.name}/{self.slug}/"
Elke keer dat deze methode werd aangeroepen, werd self.author.name
uitgevoerd,
wat leidde tot N extra queries.
Het duurde vrij lang om dit probleem op te lossen.
✅ Samenvatting: Waarom je het N+1 probleem moet begrijpen
- Terwijl je Django ORM gebruikt, kan dit probleem altijd optreden.
- Als de laadsnelheid van de pagina vertraagt, is het waarschijnlijk dat ORM meer queries uitvoert dan verwacht.
- Dit kan overal gebeuren: in sjablonen, view functies of modelmethoden.
- Naarmate er meer gegevens zijn, kan de prestatieverschlechtering ernstiger worden.
- ORM biedt geen automatische optimalisatie, dus je moet de uitgevoerde queries zelf controleren en optimaliseren.
✅ In het volgende artikel zal ik uitleggen hoe je het N+1 probleem kunt oplossen met select_related
en prefetch_related
.
댓글이 없습니다.