prefetch_related('articles') загружает одну выборку, а последующий articles.filter(deleted=False) создаёт новые запросы. В результате предварительная загрузка не устраняет N+1 для используемого фильтра.
Анализ и исправление узких мест запросов к базе данных
prefetch_related('articles') загружает одну выборку, а последующий articles.filter(deleted=False) создаёт новые запросы. В результате предварительная загрузка не устраняет N+1 для используемого фильтра.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо выявить и подробно описать проблемы в работе кода, которые снижают производительность запросов к БД. Рассмотрим функцию, получающую всех авторов и их связанные статьи.
def fetch_authors():
authors_qs = Author.objects.prefetch_related('articles').all()
for author in authors_qs:
print(f'{author.get_full_name()}:')
for article in author.articles.filter(deleted=False):
print(f' {article.name}')
Ответ
prefetch_related('articles') загружает одну выборку, а последующий articles.filter(deleted=False) создаёт новые запросы. В результате предварительная загрузка не устраняет N+1 для используемого фильтра.
Загрузите сразу нужные статьи в отдельный атрибут:
from django.db.models import Prefetch
def fetch_authors():
authors = Author.objects.prefetch_related(Prefetch(
'articles',
queryset=Article.objects.filter(deleted=False),
to_attr='visible_articles',
))
for author in authors:
print(f'{author.get_full_name()}:')
for article in author.visible_articles:
print(f' {article.name}')
Article — предполагаемая модель статьи. Проверьте также, не выполняет ли get_full_name() запросы. Для огромного числа авторов нужна порционная обработка, иначе prefetch может занять много памяти.