如果大型查询集的条件非常慢

Posted

技术标签:

【中文标题】如果大型查询集的条件非常慢【英文标题】:if condition on large querysets are very slow 【发布时间】:2019-01-19 07:51:38 【问题描述】:

我正在使用 Python 2.7 和 Django 1.9.2

我正在尝试做一个条件,如果查询集不为空,就会有一个功能。当我的查询集已经增加到 56,000 条记录时,我意识到了一些事情。使用该查询集的一个简单条件几乎需要 5 秒,但如果我在查询集中添加 .exists(),它就会非常快。

请检查下面的sn-p

from record.models import Record
records = Records.objects.filter(result=0)
if records:  # this takes almost up to 5 seconds with 56,000 records
    # do stuff here

.exists():

from record.models import Record
records = Records.objects.filter(result=0)
if records.exists():  # very fast abd just takes milliseconds
    # do stuff here

任何解释为什么第一个这么慢?我开始认为第一个循环在执行if 时会循环records 变量的值@

【问题讨论】:

【参考方案1】:

无论何时运行exists(),它都会对数据库进行快速查询。根据文档:

这会尝试以最简单和最快的方式执行查询,但它确实执行与普通 QuerySet 查询几乎相同的查询

但是,如果你直接在 IF 条件下使用查询集(或使用count()len() 等),它会得到evaluated。这就是为什么它很慢。根据文档:

bool()。 在布尔上下文中测试 QuerySet,例如使用 bool()、or、and 或 if 语句,将导致查询被执行。如果至少有一个结果,则 QuerySet 为 True,否则为 False。

另外,更多关于exists():

exists() 对于与 QuerySet 中的对象成员资格和 QuerySet 中是否存在任何对象相关的搜索非常有用,尤其是在大型 QuerySet 的上下文中。

但是,如果无论如何都要评估查询集,那么不建议使用exists(),因为它会做更多的工作。在这种情况下,您可以简单地将其用作bool(your_qset)。根据文档:

此外,如果 some_queryset 还没有被评估,但你知道它会在某个时候被评估,那么使用 some_queryset.exists() 将做更多的整体工作(一个查询存在检查加上一个额外的稍后检索结果)而不是简单地使用 bool(some_queryset),它检索结果然后检查是否返回任何结果。

更多详情,请查看documentation。

【讨论】:

但是如果我先调用records 然后使用if records.. 它很快 那个时候,结果已经缓存了。这就是为什么它很快 当我第一次调用records 本身时,它已经很快了。但是第一次调用if records很慢。。后台还有其他操作吗? 用文档中的更多详细信息更新了我的答案。基本上,当您调用记录时,会对其进行评估,并缓存结果。这就是if records 速度快的原因。 对不起,我没有看到如果记录很慢的答案。是不是因为它循环到查询集然后一一检查关键地址是否有现有的?

以上是关于如果大型查询集的条件非常慢的主要内容,如果未能解决你的问题,请参考以下文章

ORDER BY 中查询非常慢,LIMIT 范围较大

SQLite:即使有索引,大型数据库中的查询也非常慢

有条件地匹配两个大型数据集的多列中的元素

查询大型 SQL Server 表时,pymssql/pyodbc 性能(cursor.execute)非常慢

如何改进热图的大型数据集的 KQL 查询

在 R 中拆分大型数据集的有效方法