Django 使用 Q 对象优化查询集

Django Optimisation of a queryset with Q objects

我正在使用 Django 1.8。

我有一个查询集需要一个逻辑 "or" 和一个 "and"。 它给出:

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

正如您可能理解的那样,它应该获取每个不应该启动的活动 MyModel 实例,以及已经完成的实例,然后停用它们。

"start" 和 "end" 是日期字段,"active" 是布尔值。

它有效,但它生成的查询远未得到优化。我希望能够通过过滤 "active" 状态来开始查询,然后检查其他两个字段,因为在我的数据库中,我有数千个条目,但只有少数条目具有 active=True。我会说这个布尔测试比比较更快。

我无法对参数重新排序,因为前者带有两个 Q() 是一个定位参数,而后者是一个名称参数,我无法链接多个 filter() 因为它会生成一个 "or",而不是 "and".

有办法吗?

您可以通过 chaining filters

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

补充说明

我认为您不会通过先过滤 active 然后过滤 startend 来获得任何性能提升。因为 chaning 或 not-chaining 将执行相同的查询。这是来自 Django docs 的示例:

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

In SQL terms, that evaluates to:

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

请注意,过滤器已在上面的示例中链接在一起,但在 SQL 查询中,两个过滤器被放在一起。

提升数据库性能

  1. 查找数据库索引(如评论中所指出)。

  2. 考虑在内存中缓存数据库(例如,参见 Memcached)。

首先,Django ORM 生成的 SQL 命令可能不会具有与您的 .filter 方法相同顺序的条件子句。所以不用担心 "optimal" 顺序。

其次,无论子句以何种顺序出现在SQL命令中,数据库引擎都会优化请求并生成适合您的数据分布的执行计划。任何值得考虑的数据库引擎都会保留一些数据分布统计信息。如果active条记录的比例实际上是本次查询中的最佳判别式,则优先过滤