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 предоставляет выше, но в менее многословной усадьбе (как в Примере rails, где всего 19 символов фиксируют N+1 и очень ясно)? Кроме того, пакетный выбор решает проблему таким же образом, или это две разные вещи?
Кстати, я не спрашиваю о select_related
, хотя на первый взгляд это может показаться ответом. взгляд. Я говорю о ситуации, когда address
имеет ключ forign к client
.
3 ответа:
Вы можете сделать это с prefetch_related начиная с Django 1.4: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
Если вы используете https://github.com/ionelmc/django-prefetch
Он утверждает, что является более гибким, чем prefetch_related Джанго. Многословен, но отлично работает.
К сожалению, ОРМ Джанго пока не может этого сделать.
К счастью, это можно сделать всего за 2 запроса, с небольшим количеством работы, выполненной в 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]
Django-batch-select должен дать ответ на эту проблему, хотя я еще не пробовал его. Ответ Игнасио выше кажется мне лучшим.