Django обращается к базе данных для каждого вызова filter () - PullRequest
2 голосов
/ 26 мая 2011

У меня есть некоторый код Django 1.3, который просматривает множество экземпляров модели в цикле, т. Е.

my_set = myinstance.subitem_set.all()

for value in values:
  existing = my_set.filter(attr_name=value)
  if len(existing) == 1:
     ...

Это работает, но профилирование SQL-запросов показывает, что оно обращается к БД на каждой итерации. Согласно https://docs.djangoproject.com/en/1.3/ref/models/querysets/ итерации по связанным элементам должны охотно загружать их, поэтому я попытался позвонить:

list(my_set)

Однако это не помогает. Он выполняет запрос для загрузки всех подпунктов, но затем все равно выполняет отдельный запрос для каждого подпункта внутри цикла. Как заставить его использовать кэшированный набор и не каждый раз попадать в БД? БД - это PostgreSQL 8.4.

1 Ответ

5 голосов
/ 26 мая 2011

Проблема в этой строке:

if len(existing) == 1:

Из документации Django:

LEN (). QuerySet оценивается, когда вы вызываете len () для него. Это, как и следовало ожидать, возвращает длину списка результатов.

Примечание. Не используйте len () в QuerySets, если все, что вам нужно, это определить количество записей в наборе. Гораздо эффективнее обрабатывать счет на уровне базы данных, используя SQL SELECT COUNT (*), и Django предоставляет метод count () именно по этой причине. Смотрите count () ниже.

Так что в вашем случае он выполняет запрос каждый раз, когда вы вызываете len(existing). Более эффективный способ:

existing.count() == 1

Это также будет попадать в базу данных при каждом вызове, но будет выполняться SELECT COUNT(*), что быстрее.

...