Сколько SQL-запросов выполняется при использовании join в Django ORM
Что проверяют
Понимаете ли вы, что ORM ленив и что число запросов задаёт не слово join, а способ, которым вы попросили связанные данные. Заодно проверяют, ловили ли вы на практике лишние запросы по схеме N плюс один.
Как отвечать
Честный ответ начинается с уточнения: смотря какая связь и чем она загружается. Дальше разложите варианты.
Сам по себе queryset ничего не выполняет: запрос уходит при итерации, срезе или подсчёте длины. Если связанный объект не загружен заранее, обращение к нему делает отдельный запрос на каждую запись, и получается один запрос на список плюс по одному на строку.
select_related строит один запрос с соединением и подходит для ForeignKey и OneToOne в сторону одного объекта. prefetch_related соединения не делает: он выполняет отдельный запрос на каждый уровень связи и склеивает результаты уже в Python, поэтому он для обратных связей и для многие ко многим. Вложенную выборку настраивают через Prefetch.
Фильтр по полю связанной модели добавляет соединение сам, без дополнительных методов. Но цепочка из двух фильтров по многозначной связи даст два разных соединения, а один фильтр с двумя условиями одно.
with CaptureQueriesContext(connection) as ctx:
list(Book.objects.select_related("author"))
len(ctx)Где спотыкаются
Называют число, не спросив про связь. Один запрос это правда только про select_related, у prefetch_related их столько, сколько уровней, а без того и другого столько, сколько записей в выборке.
Второе: тянут select_related на многие ко многим или на обратную связь. Там соединение размножает строки, выборка раздувается, и вместо экономии получается перекачка одних и тех же данных из базы.
Третье: проверяют на глаз. На десятке записей в локальной базе лишние запросы незаметны, поэтому счётчик закрепляют тестом через assertNumQueries, а на сервере смотрят в панель отладки или в логи медленных запросов.