Решение Django N + 1
Я посетил http://guides.rubyonrails.org/active_record_querying.html после разговора с одноранговым узлом относительно N + 1 и серьезных последствий для плохих запросов БД.
ActiveRecord (Rails):
clients = Client.includes(:address).limit(10)
Если у клиента есть адреса, и я намереваюсь получить к ним доступ во время цикла через клиентов, Rails предоставляет includes
, чтобы он знал, чтобы продолжить и добавить их в запрос, что устраняет 9 запросов сразу с места в пути.
Джанго:
https://github.com/lilspikey/django-batch-select обеспечивает поддержку пакетного запроса. Знаете ли вы о других библиотеках или трюках для достижения того, что Rails предоставляет выше, но в менее сложной усадьбе (как в примере с рельсами, где всего 19 символов фиксируют N + 1 и очень ясны)? Кроме того, пакетный выбор выдает проблему таким же образом или эти две разные вещи?
Кстати, я не спрашиваю о select_related
, хотя это может показаться ответом на первый взгляд. Я говорю о ситуации, когда address
имеет знаковый символ client
.
Ответы
Ответ 1
Вы можете сделать это с помощью prefetch_related с Django 1.4:
https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
Если вы используете < 1.4, посмотрите на этот модуль:
https://github.com/ionelmc/django-prefetch
Он утверждает, что он более гибкий, чем Django prefetch_related. Подробно, но отлично работает.
Ответ 2
К сожалению, Django ORM пока еще не может этого сделать.
К счастью, это возможно сделать только в двух запросах, с небольшим количеством работы, выполненной в Python.
clients = list(Client.objects.all()[:10])
addresses = dict((x.client_id, x) for x in
Address.objects.filter(client__in=clients))
for client in clients:
print client, addresses[client.id]
Ответ 3
django-batch-select должен предоставить ответ на эту проблему, хотя я не пробовал ее. Ответ Игнасио выше кажется мне лучшим.