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 оба фильтра взяты вместе.
Для повышения производительности БД
Посмотрите индексирование БД (как указано в комментариях).
Учитывая кеширование базы данных в памяти (см., Например, Memcached).