Узнайте, как избежать проблемы N+1 в Django REST Framework
3 апреля 2023 г.Проблема N+1 — это распространенная проблема, которая может возникнуть при использовании Django REST сериализатор фреймворка. Это происходит, когда код выполняет несколько запросов к базе данных для извлечения связанных данных вместо использования одного запроса с оператором JOIN. Это может значительно снизить производительность вашего приложения.
Один из способов решить эту проблему — использовать методы select_related
и prefetch_related
в вашем наборе запросов. Эти методы позволяют указать, какие связанные данные следует извлекать в одном запросе к базе данных, что сокращает количество необходимых запросов.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# Without select_related
books = Book.objects.all()
for book in books:
print(book.author.name) # This will make a separate database query for each book
# With select_related
books = Book.objects.select_related('author').all()
for book in books:
print(book.author.name) # This will make only one database query
В этом примере у нас есть две модели: Автор
и Книга
. Модель Book
имеет внешний ключ для модели Author
. Без использования select_related
получение имени автора для каждой книги потребовало бы отдельного запроса к базе данных для каждой книги. Используя select_related
, мы можем получить все связанные данные в одном запросе.
связанный с select и prefetch_related
==tl;dr== n select_related
используется для отношений "один к одному" и "многие к одному", тогда как prefetch_related
используется для отношений "один к одному". связи "многие" и "многие ко многим".
select_related
и prefetch_related
— это два метода в Django ORM, которые могут помочь уменьшить количество запросов к базе данных. select_related
используется для извлечения связанных объектов в одном запросе, когда вы знаете, что будете обращаться к связанным объектам. Он работает путем создания соединения SQL и включения полей связанного объекта в инструкцию SELECT.
n С другой стороны, prefetch_related
выполняет отдельный поиск для каждой связи и выполняет «соединение» в Python. Это может быть более эффективно при работе с отношениями "многие ко многим" или "многие к одному".
выбрать_связанный
select_related
– это метод, который можно использовать в Django QuerySet для оптимизации запросов к базе данных при извлечении связанных данных. Он работает путем создания оператора SQL JOIN для извлечения связанных данных в одном запросе вместо создания нескольких запросов.
select_related
полезен, когда у вас есть внешний ключ или взаимосвязь между двумя моделями. Вы можете использовать его, чтобы указать, какие связанные поля должны извлекаться в том же запросе, что и основная модель.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# Without select_related
books = Book.objects.all()
for book in books:
print(book.author.name) # This will make a separate database query for each book
# With select_related
books = Book.objects.select_related('author').all()
for book in books:
print(book.author.name) # This will make only one database query
В этом примере у нас есть две модели: Автор
и Книга
. Модель Book
имеет внешний ключ для модели Author
. Без использования select_related
получение имени автора для каждой книги потребовало бы отдельного запроса к базе данных для каждой книги. Используя select_related
, мы можем получить все связанные данные в одном запросе.
prefetch_related
prefetch_related
— это еще один метод, который вы можете использовать в Django QuerySet для оптимизации запросов к базе данных при извлечении связанных данных. Он работает, получая связанные данные в отдельном запросе, а затем связывая их с основной моделью в Python.
prefetch_related
полезен, когда между двумя моделями имеется отношение «многие ко многим» или обратное отношение внешнего ключа. Вы можете использовать его, чтобы указать, какие связанные поля должны быть извлечены в отдельном запросе, а затем связаны с основной моделью.
from django.db import models
class Author(modpels.Model):
name = models.CharField(max_length=100)
books = models.ManyToManyField('Book')
class Book(models.Model):
title = models.CharField(max_length=100)
# Without prefetch_related
authors = Author.objects.all()
for author in authors:
print(author.name)
for book in author.books.all():
print(book.title) # This will make a separate database query for each author
# With prefetch_related
authors = Author.objects.prefetch_related('books').all()
for author in authors:
print(author.name)
for book in author.books.all():
print(book.title) # This will make only two database queries
В этом примере у нас есть две модели: Author
и Book
, между которыми существует отношение «многие ко многим». Без использования prefetch_related
для получения книг каждого автора потребовался бы отдельный запрос к базе данных для каждого автора. Используя prefetch_related
, мы можем получить все связанные данные в двух запросах: один для авторов и один для книг.
:::подсказка В дополнение к примерам кода для редактирования этой статьи использовался сайт copy.ai.
:::
Оригинал