簡體   English   中英

Django:prefetch_related無效

[英]Django: prefetch_related has no effect

我正在嘗試使用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是訂單數)。

由於OrderOperation僅包含單個相關字段total ,因此更好的方法是使用查詢來注釋原始查詢中最新操作的總數:

from django.db.models import OuterRef, Subquery
newest = OrderOperation.objects.filter(post=OuterRef('pk')).order_by('-created_at')  # or whatever the timestamp field is
orders = Order.objects.annotate(newest_operation_total=Subquery(newest.values('total')[:1]))

我在這里發布答案,你能告訴我這是否有意義嗎?

而不是調用的latest()如果我只是得到第一個項目在我的查詢集有[0]或最后用len(qs)-1 ,假設order_operations已經訂購?

@property
def last_operation(self) -> Optional['OrderOperation']:
    try:
        qs = self.orderoperation_set.all()
        return qs[len(qs) - 1]
    except IndexError:
        return None

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM