【问题标题】:Django: Is it possible to achieve the same thing as sql's exists?Django:是否有可能实现与 sql 存在相同的事情?
【发布时间】:2012-03-19 20:26:32
【问题描述】:

为了让我的问题更容易理解,这里有一个例子。

有两种型号:

class A(models.Model):
    name = models.CharField(max_length = 10)

class B(models.Model):
    a = models.ForeignKey(A)
    name = models.CharField(max_length = 10)

所以在这个例子中,A 和 B 是一对多的关系。现在假设我要进行以下查询:找到一个至少有一个 B 作为孩子的 A。在sql中,显然我应该使用exists子句。用orm能做到完全一样吗?

我对此进行了一些研究,但找不到与 sql 查询完美匹配的内容。最接近的解决方案是:

A.objects.filter(b__pk__gt = 0).distinct()

但是离sql中的exists子句还差得很远,可能没有exists那么高效。

【问题讨论】:

    标签: python django


    【解决方案1】:

    以下将选择具有一个或多个关联Bs 的所有As:

    A.objects.filter(b__isnull=False)
    

    将其切换为b__isnull=True 将仅选择没有Bs 关联的As。

    【讨论】:

    • 所以使用 b__isnull=False,我不再需要附加 distinct 了?它是 sql 中真正的存在子句?
    • 您不需要 distinct,但我不确定它究竟执行了什么查询。然而,这是最好的 Django ORM。否则,直接使用raw的SQL即可。
    • 在竭尽全力优化之前获得正确答案。如果您真的必须深入了解 ORM 的 SQL,请尝试:import django; django.db.connection.queries from ./manage.py shell。
    • 我试了一下,发现这个简单的查询不需要 distinct。但是假设我现在想做一个查询,比如“找到一个至少有一个名为 Test 的 B 作为子级的 A”,那么我必须将其写为 A.objects.filter(b__isnull=False, b__name = 'Test' )。清楚的()。所以总而言之,它可以实现与exists子句相同的功能,但距离真正的exists子句还差得很远。
    • 你不需要b_isnull=False,在这种情况下, distinct 并不是获得A 的最佳方式。相反,您应该使用:a = A.objects.filter(b__name='Test')[0]。或者,如果您只是想测试它是否存在(不检索对象),请使用:A.objects.filter(b__name='Test').exists()
    【解决方案2】:

    实际上(如果我没有误解您要做什么)使用普通 sql,一个简单的左连接将是代替 EXISTING 子句的方法。

    您的查询集在没有 .distinct() 的情况下工作得很好

    我建议你看看 django orm 生成的查询,这样你就可以看到发生了什么并实际运行 ANALYZE/EXPLAIN 而不是猜测性能。

    您可以从查询集的查询属性中查看原始查询,或者更好的是,安装 django 调试工具栏并查看给定请求的所有查询。

    【讨论】:

    • +1 用于调试工具栏。如果您查看查询,您可能会发现A.objects.exclude(b__isnull=True) 执行左外连接,...filter(b__isnull=False) 执行内连接。
    • @istruble 确实,加入是这种查询的方式
    • 对不起。但我不同意你的存在与简单的左加入评论。我的例子只是寻找一个有一个 B 孩子的 A。我对 B 没有过滤器。所以存在或替换它是自然选择。
    • @GeorgiePorgie 很难说哪个性能更好,这就是为什么如果你真的关心该查询的性能,我建议你查看解释输出。就逻辑而言,如果您不需要使用表 b 中的数据,那么您是对的,存在更适合(即使最终结果具有可比性):)
    猜你喜欢
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    • 2013-12-26
    • 2021-10-05
    • 2021-04-08
    • 2018-11-30
    • 1970-01-01
    相关资源
    最近更新 更多