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 11

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 должен дать ответ на эту проблему, хотя я еще не пробовал его. Ответ Игнасио выше кажется мне лучшим.