优化djangos最新查询庞大的集合

时间:2014-09-16 12:54:56

标签: django postgresql optimization

class Offer(models.Model):
    match = models.ForeignKey(Match, related_name='offers')
    # arbitrary information

class Odds(models.Model):
    offer = models.ForeignKey(Offer, related_name='odds')
    time = models.DateTimeField(db_index=True)

    class Meta:
        get_latest_by = 'time'

    # arbitrary information

我有一大堆Offer s,我需要获取latest Odds个对象。我现在正在执行的查询是以下

for m in Match.objects.all():
    odds = [o.odds.latest() for o in m.offers.all()]

连接到Odds的其余Offer个对象是出于历史目的而存储的,不应用于随后的计算中。

问题是,这会为每个Offer对象计算一个查询,这是一个巨大的时间和性能因素,我正在努力解决这个问题。

TLDR; 我希望使用Odds为每个Offer获取一个ORDER BY time个对象。

真正感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

您可以使用prefetch_related。它为每个关系进行单独查找,并在Python中进行“加入”,而不是代码中的许多小查询。

对于Django 1.6及更早版本:

class Offer(models.Model):
    match = models.ForeignKey(Match, related_name='offers')

    def latest_odds(self):
        return max(self.odds.all(), key=lambda odds: odds.time)
...

for m in Match.objects.all().prefetch_related('offers__odds'):
    odds = [o.latest_odds() for o in m.offers.all()]

---------
3 queries

在Django 1.7中,有一个Prefetch()对象,允许您控制prefetch_related的行为:

for m in Match.objects.all().prefetch_related(Prefetch("offers__odds", queryset=Odds.objects.order_by('time'))):
    odds = [o.odds.first() for o in m.offers.all()]

---------
3 queries

如果Odds真的很大,你应该看看非规范化表