Как метод select_related оптимизирует запросы в Django?

Ответ

select_related() — это метод Django ORM для оптимизации производительности, который решает проблему "N+1 запросов". Он "жадно" загружает связанные объекты через FOREIGN KEY или OneToOne в одном SQL-запросе с помощью JOIN.

Это позволяет избежать дополнительных обращений к базе данных при доступе к связанным моделям в цикле.

Проблема: N+1 запросов

Без select_related() для каждой книги будет выполнен отдельный SQL-запрос для получения автора.

# models.py
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)

# views.py
# Выполняется 1 запрос для получения всех книг
books = Book.objects.all()

# В цикле для каждой из N книг выполняется еще 1 запрос к автору
for book in books:
    print(f'"{book.title}" от {book.author.name}') # <-- Здесь происходит N доп. запросов

Решение: select_related()

Все данные о книгах и их авторах загружаются за один SQL-запрос.

# Выполняется 1 запрос, который объединяет таблицы Book и Author
books = Book.objects.select_related('author').all()

# Дополнительных запросов к БД нет, данные уже загружены
for book in books:
    print(f'"{book.title}" от {book.author.name}')

Важные моменты:

  • Типы связей: Работает только для ForeignKey и OneToOne.
  • Направление: Следует по "прямым" связям (не по обратным).
  • Альтернатива: Для связей ManyToManyField и обратных ForeignKey используется prefetch_related(), который выполняет отдельный запрос и "соединяет" данные в Python.