【问题标题】:(Django) Efficiently get related objects from a ManyToManyField, sorted and limited to a count(Django) 有效地从 ManyToManyField 中获取相关对象,排序并限制为计数
【发布时间】:2021-03-26 18:31:04
【问题描述】:

我有一个超过 50k 人的数据库。每个 Person 可以拥有多个 Item,每个 Item 可以被多个 Person 拥有。 Person 包含字段 Items,其类型为 ManyToManyField()。

我需要获取 100 个 Person 对象,按拥有的项目数排序。同样对于每个人,我需要 10 个项目,按“稀有度”字段(只是一个数字)排序。

问题是查询的第一部分(获取 Person 对象)非常快,而第二部分花费的时间要长 100 倍,这是有道理的,因为我可以看到它对每个 Person 进行单独的查询。

这是我的代码:

persons = Person.objects.all().order_by('-items_count')[:100]

for person in persons:
    items = person.items.all().order_by('rarity')[:10]

    # Do stuff, build a response object

items_count 是一个预先计算的字段,其中包含拥有的项目数。我知道我可以即时对其进行注释,我只是在尝试优化查询。

整个过程需要一秒钟。有没有办法将两个查询合并为一个,或者以某种方式更改我的模型来优化它?

这是我的模型:

class Item(models.Model):
    name = models.CharField(max_length=50)
    # Other fields...

class Person(models.Model):
    name = models.CharField(max_length=50)
    items = models.ManyToManyField(Item, related_name='owners')
    # Other fields...

【问题讨论】:

    标签: django postgresql django-models


    【解决方案1】:

    您应该查看QuerySet.prefetch_related。文档中的示例很好地解释了用法。

    我认为它应该看起来像这样:

    persons = Person.objects.all().prefetch_related("items")
    

    【讨论】:

    • 我让它工作了,但是一旦我尝试对相关项目进行排序,它就会执行另一个查询。我找不到在prefetch_related 中包含排序或其他查询参数的方法。
    • 我让它工作了,但它对性能没有影响。我看到服务器只进行一个查询,但它需要的时间与之前组合的所有查询一样长。
    • 有趣。你能用 SQL 术语展示查询的样子吗?您可以通过print(queryset.query) 进行操作。
    猜你喜欢
    • 2021-04-04
    • 2019-07-12
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-02-28
    • 1970-01-01
    • 2023-04-01
    • 2020-04-22
    相关资源
    最近更新 更多