Django查询集优化-防止选择带注释的字段

问题描述 投票:0回答:1

假设我有以下型号:

class Invoice(models.Model):
    ...

class Note(models.Model):
    invoice = models.ForeignKey(Invoice, related_name='notes', on_delete=models.CASCADE)
    text = models.TextField()

并且我想选择有一些注释的发票。我将使用annotate / Exists这样写它:

Invoice.objects.annotate(has_notes=Exists(Note.objects.filter(invoice_id=OuterRef('pk')))).filter(has_notes=True)

这效果很好,仅过滤带有注释的发票。但是,此方法导致字段出现在查询结果中,这我不需要,并且意味着性能较差(SQL必须执行两次子查询)。

我知道我可以像这样使用extra(where=)编写此代码:

extra(where=)

这将产生理想的SQL,但通常不建议使用Invoice.objects.extra(where=['EXISTS(SELECT 1 FROM note WHERE invoice_id=invoice.id)']) /原始SQL。有更好的方法吗?

python django django-queryset django-1.11 django-annotate
1个回答
0
投票

[好,我刚刚在extra中注意到,他们已经更新了Django 3.0 docs的工作方式,并且可以直接在Exists中使用:

filter

这将确保子查询不会被添加到SELECT列中,这可能会导致更好的性能。

在Django 3.0中已更改:

在以前的Django版本中,必须先进行注释,然后再对注释进行过滤。这导致带注释的值始终出现在查询结果中,并且经常导致查询花费更多的时间来执行。

[不过,如果有人知道Django 1.11的更好方法,我将不胜感激。我们确实需要升级:(

© www.soinside.com 2019 - 2024. All rights reserved.