Узнайте, как избежать проблемы N+1 в Django REST Framework

Узнайте, как избежать проблемы 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.

:::


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE