带有 Q 对象的查询集的 Django 优化

Posted

技术标签:

【中文标题】带有 Q 对象的查询集的 Django 优化【英文标题】:Django Optimisation of a queryset with Q objects 【发布时间】:2015-08-19 09:22:09 【问题描述】:

我正在使用 Django 1.8。

我有一个需要逻辑“或”和“与”的查询集。 它给出了:

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

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

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

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

我无法重新排序参数,因为带有两个 Q() 的前者是定位参数,而后者是名称参数,并且我不能链接多个 filter(),因为它会生成“或”,而不是“和”。

有没有办法做到这一点?

【问题讨论】:

添加适当的索引有什么问题? 我不明白你在问什么(或者因为我对 Django 很陌生,或者因为我不是以英语为母语的人) 这不是 Django 的东西,而是数据库的东西。 参考db_index:docs.djangoproject.com/en/1.8/ref/models/fields/#db-index 我认为在这种情况下使用索引是一件好事,因为它加速了执行,但我认为它不会改变查询的执行方式。我已经在这个字段上有一个索引。 【参考方案1】:

首先,由 Django ORM 生成的 SQL 命令的条件子句的顺序可能与您的 .filter 方法的顺序不同。所以不要担心“最佳”顺序。

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

【讨论】:

谢谢!我对此一无所知!我对 Django 很陌生,但是我已经使用了一些数据库引擎一段时间,主要是在 php 中,而且似乎我已经失去了很多时间来尝试以一种并不重要的方式优化我的查询在末尾!至少我会知道它的未来!【参考方案2】:

您可以通过 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')

在 SQL 术语中,计算结果为:

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

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

提升数据库性能

    查找数据库索引(如 cmets 中所指)。

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

【讨论】:

我一定会看看我的生产服务器的 memcached。感谢您的回答和建议。

以上是关于带有 Q 对象的查询集的 Django 优化的主要内容,如果未能解决你的问题,请参考以下文章

使用带有外键的 Q 对象定义 django 查询集

如何找到两个 Django 查询集的交集?

需要根据找到的 Q 对象来注释 Django querySet

Django框架——Q查询进阶ORM查询优化事务操作字段类型字段参数AjaxContent—Typeajax携带文件

带有Q和多个类别的django查询

Django基础之模型(models)层