Django:prefetch_related无效

我正在尝试优化数据库查询,prefetch_related但没有成功。


models.py

class Order(models.Model):

    # some fields ...


    @property

    def last_operation(self) -> Optional['OrderOperation']:

        try:

            return self.orderoperation_set.latest()

        except OrderOperation.DoesNotExist:

            return None


    @property

    def total(self) -> Optional[Decimal]:

        last_operation = self.last_operation

        return last_operation.total if last_operation else None


class OrderOperation(TimeStampable, models.Model):

    order = models.ForeignKey(Order)

    total = DecimalField(max_digits=9, decimal_places=2)

运行一个shell,我可以看到问题所在:

orders = Order.objects.prefetch_related('orderoperation_set')  # There are 1000 orders

result = sum([order.total for order in orders])

len(connection.queries)

>>> 1003

我们可以看到,每个查询有一个查询order.total,因此有1000个查询,这使整个请求非常糟糕,性能与订单数成线性关系。


为了理解为什么会这样,我在prefetch_related Django doc中找到了这个:


请记住,与QuerySet一样,任何暗示不同数据库查询的后续链接方法都将忽略先前缓存的结果,并使用新的数据库查询来检索数据。


因此,latest()每次调用都运行一个新查询似乎很正常。


在这种情况下,您将如何提高性能?(而不是N进行一些查询,其中N是订单数)。


三国纷争
浏览 250回答 2
2回答

慕尼黑8549860

由于OrderOperation仅包含单个相关字段,因此total,更好的方法是使用子查询来注释原始查询中最新操作的总和:from django.db.models import OuterRef, Subquerynewest = OrderOperation.objects.filter(post=OuterRef('pk')).order_by('-created_at')  # or whatever the timestamp field isorders = Order.objects.annotate(newest_operation_total=Subquery(newest.values('total')[:1]))

手掌心

我在这里发布答案,你能告诉我这是否有意义吗?而不是调用的latest(),如果我只是得到我的查询集与第一项[0](或最后用len(qs)-1,假设order_operations已经订购?@propertydef last_operation(self) -> Optional['OrderOperation']:    try:        qs = self.orderoperation_set.all()        return qs[len(qs) - 1]    except IndexError:        return None
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python