Django Оптимизация набора запросов с объектами Q

Я использую Django 1.8.

У меня есть набор запросов, который требует логического "или" и "и". Это дает:

MyModel.objects.filter(
    Q(start__gt=today) | Q(end__lte=today),
    active=True).update(active=False)

Как вы, возможно, понимаете, он должен взять все активные экземпляры MyModel, которые еще не должны были начаться, и тот, который завершился, и деактивировать их.

"start" и "end" - поля DateFields, а "active" - логическое значение.

Это работает, но генерирует запрос, который далек от оптимизации. Я хотел бы иметь возможность запустить запрос путем фильтрации по "активному" состоянию, а затем проверить два других поля, потому что в моей базе данных есть тысячи записей, но только немногие из них имеют active=True. Я бы сказал, что этот логический тест быстрее, чем сравнения.

Я не могу переупорядочить аргументы, потому что первый с двумя Q() является позиционированным аргументом, в то время как последний является аргументом имени, и я не могу связать несколько filter(), потому что он генерирует "или", а не "а также".

Есть ли способ сделать это?

2 ответа

Решение

Прежде всего, команда SQL, сгенерированная Django ORM, вероятно, не будет иметь условия условия в том же порядке, что и ваши .filter методы. Так что не беспокойтесь об "оптимальном" порядке.

Во-вторых, независимо от того, в каком порядке появляются предложения в команде SQL, механизм БД оптимизирует запрос и генерирует план выполнения, адаптированный к вашему распределению данных. Любой движок БД, который стоит рассмотреть, ведет статистику распределения данных. Если доля active На самом деле записи - лучший дискриминант в этом запросе, тогда он будет отфильтрован первым.

Вы можете сделать это с помощью цепочки фильтров

MyModel.objects.filter(
    active=True
).filter(
    Q(start__gt=today) | Q(end__lte=today)
).update(active=False)

Дополнительные примечания

Я не думаю, что вы получите прирост производительности при первой фильтрации active а затем фильтрация start а также end, Потому что изменение или нет - выполнение одного и того же запроса. Вот пример из документации Django:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

В терминах SQL это оценивает:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

Обратите внимание, что в приведенном выше примере фильтры были объединены в цепочку, однако в запросе SQL оба фильтра взяты вместе.

Для повышения производительности БД

  1. Посмотрите индексирование БД (как указано в комментариях).

  2. Учитывая кеширование базы данных в памяти (см., Например, Memcached).

Другие вопросы по тегам