Select и prefetch related: работа с БД для конкретной логики | OTUS
🚀 OTUS Fest 2021
Бесплатная образовательная онлайн-конференция для IT-специалистов.
Подробнее

Курсы

Программирование
Backend-разработчик на PHP
-9%
Алгоритмы и структуры данных
-9%
Team Lead
-6%
Архитектура и шаблоны проектирования Разработчик IoT
-13%
C# Developer. Professional
-9%
HTML/CSS
-11%
C# ASP.NET Core разработчик
-5%
Kotlin Backend Developer
-8%
iOS Developer. Professional
-8%
Java Developer. Basic C++ Developer. Professional Web-разработчик на Python MS SQL Server Developer Android Developer. Basic Разработчик программных роботов (RPA) на базе UiPath и PIX Microservice Architecture Unity Game Developer. Basic Разработчик голосовых ассистентов и чат-ботов React.js Developer Node.js Developer Интенсив «Оптимизация в Java» Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes JavaScript Developer. Basic Unity Game Developer. Professional Супер-интенсив Azure
Инфраструктура
Экспресс-курс «IaC Ansible»
-10%
Administrator Linux.Basic
-10%
Мониторинг и логирование: Zabbix, Prometheus, ELK
-10%
Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes»
-30%
Administrator Linux. Professional
-6%
Дизайн сетей ЦОД
-13%
NoSQL Основы Windows Server MS SQL Server Developer Инфраструктурная платформа на основе Kubernetes Cloud Solution Architecture Highload Architect Разработчик голосовых ассистентов и чат-ботов VOIP инженер Супер-практикум по работе с протоколом BGP Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Супер-интенсив "Tarantool"
Специализации Курсы в разработке Подготовительные курсы
+7 499 938-92-02

Select и prefetch related: работа с БД для конкретной логики

WebDev_Deep_27.07_ышеу.png

В Django ORM есть много способов отойти от стандартных запросов, которые генерируются при запросах вида Book.objects.filter(category_id=category_id), и сделать работу с БД оптимальной для конкретной логики.

Среди подобных методов отдельное место занимают select_related и prefetch_related. Во-первых, в некоторых случаях они позволяют десятком символов снизить нагрузку на БД на порядок. Во-вторых, при неправильном их использовании можно убить приложение. А в-третьих, на собеседованиях на позицию начинающего веб-разработчика почти никто не может рассказать о разнице между ними.

Рассмотрим пример

class Book(Model):
    category = ForeignKey(Category)
    authors = ManyToManyField(Author)
…
book = Book.objects.get(pk=book_id)
print(book.category.name)
print([a.full_name for a in book.authors.all()])
print([a.pk for a in book.authors.all()])

Такой код сгенерирует четыре запроса: вытащит книгу, потом категорию, потом авторов, чтобы вывести их имена, потом опять авторов, чтобы вывести их номера. Было бы классно снизить количество запросов: авторов вытаскивать один раз, а категорию вытаскивать одним запросом с книгой.

Давайте начнём с категории

Тут нам пригодится select_related:

Book.objects.select_related(‘category’).get(pk=book_id)

за один запрос вытащит и книгу и категорию и тогда book.category.name уже не сгенерирует запроса.

Круто: мы сэкономили один запрос и не получили никаких штрафов. Хочется проделать нечто подобное с авторами, но увы: select_related(‘authors’) сделать не получится.

Всё дело в том, что тут отношение «многие ко многим», а в этом случае нельзя просто взять, сделать join и за один запрос вытащить и книгу, и всех авторов.

Тут-то и пригодится prefetch_related

Вот так:

Book.objects.prefetch_related(‘authors’).get(pk=book_id)

Здесь произойдёт два запроса: один вытащит книгу, а другой – всех авторов. Объединит их уже ORM на стороне Python. Теперь

print([a.full_name for a in book.authors.all()])

не сгенерирует ни одного запроса: всё уже есть.

Как видите, select_related и prefetch_related – мощные команды, которые работают совсем по-разному. Используйте их к месту, радуйте своих DBA и спите спокойно!

Есть вопрос? Напишите в комментариях!

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
1 комментарий
1

Очень жизненно, когда ты сам администратор баз ;)

Для комментирования необходимо авторизоваться