运行了很多查询

时间:2012-07-24 13:35:13

标签: django django-models

我的方法有以下模型:

class TrendingTopic(models.Model):

    categories = models.ManyToManyField('Category', through='TTCategory', blank=True, null=True)
    location = models.ForeignKey(Location)


    def get_rank(self, t_date=None):
        if t_date:
            ttcs = self.trendingtopiccycle_set.filter(cycle_time__gt=t_date)
        else:
            ttcs = self.trendingtopiccycle_set.all()
        if ttcs:
            return sum([ttc.rank for ttc in ttcs])/len(ttcs)
        return 0

    def get_day_rank(self,t_date):
        ttcs = self.trendingtopiccycle_set.filter(cycle_time__year=t_date.year,
                                            cycle_time__month=t_date.month,
                                            cycle_time__day=t_date.day)
        sum_rank = sum([ttc.day_rank for ttc in ttcs if ttc.day_rank])
        if sum_rank:
            return sum_rank/len(ttcs)
        return 0 


class TrendingTopicCycle(models.Model):

    tt = models.ForeignKey(TrendingTopic)

    cycle_time = models.DateTimeField(default=datetime.now)
    from_tt_before = models.BooleanField(default=False)
    rank = models.FloatField(default=0.0)
    day_rank = models.FloatField(default=0.0)   

然后我在视图中使用了一些函数来检索所需的信息:

  • 显示当天最热门的热门话题:

    def day_topics(tt_date, limit=10):
    
        tts = [(ttc.tt, ttc.tt.get_day_rank(tt_date)) for ttc in \
            TrendingTopicCycle.objects.distinct('tt__name') \
            .filter(cycle_time__year=tt_date.year,
                    cycle_time__month=tt_date.month,
                    cycle_time__day=tt_date.day)]
        sorted_tts = sorted(tts, key=itemgetter(1), 
                       reverse=True)[:limit]
        return sorted_tts   
    
  • 在确定的时间内显示给定位置(woeid)的最佳热门主题:

    def hot_topics(woeid=None, limit=10):
    
        CYCLE_LIMIT = datetime.now() + relativedelta(hours=-5)
        TT_CYCLES_LIMIT = datetime.now() + relativedelta(days=-2)
        if woeid:
            tts = [ttc.tt for ttc in \
                    TrendingTopicCycle.objects.filter(tt__location__woeid=woeid) \
                    .distinct('tt__name') \
                    .exclude(cycle_time__lt=CYCLE_LIMIT)]
        else:
            tts = [ttc.tt for ttc in \
                    TrendingTopicCycle.objects.distinct('tt__name') \
                    .exclude(cycle_time__lt=CYCLE_LIMIT)]
    
    
        sorted_tts = sorted(tts, key=lambda tt: tt.get_rank(TT_CYCLES_LIMIT),
                    reverse=True)[:limit]    
        return sorted_tts
    

当前解决方案的问题在于它运行速度非常慢,因为它执行了大量查询(100次)来检索数据。我正在使用django调试工具栏来帮助我测量性能。

显然,我正在做一些非常错误的事情,我正在寻找解决方案,我们将非常感谢任何帮助。

编辑:

每个趋势主题都有一组趋势主题周期(ttc)。每个ttc有两个等级:一般(等级)和day_rank。趋势主题等级是通过每个ttc循环计算的。

2 个答案:

答案 0 :(得分:1)

首先,请注意django-debug-toolbar虽然很棒,但本身非常慢。如果您注释掉其中间件,则响应时间会显着提高 。这是一个非常有用的工具,不要误会我的意思。我虔诚地使用它,但重点是你不能在你的网站上以“慢速”这样的主观内容为基础进行基准测试。

其次,您的代码有点混乱,因此很难确切地说出您应该做什么。例如,TrendingTopicCyclerankday_rank字段,但您从不在发布的代码中使用它们。每次调用get_day_rank都会发出一个查询,所以如果你只能过滤day_rank字段本身(不需要那个查询)显然会更有效率,但我无法从代码中看出你如果或当这些字段实际设置时,请在此处。

您可以对代码进行一些小改进,明智地使用select_related。例如,每次在列表推导中运行ttc.tt.get_day_rank(tt_date))时,都会发出一个查询以获取tt,然后在get_day_rank中发出另一个查询。只需将.select_related('tt')添加到您的查询集即可至少消除tt的查询。

另外,我不确定它是否真的导致Django发出不同的查询(也许是一个效率更低的查询),但无论如何,单独过滤year,{{1 }}, month,只过滤完整日期,即:

day

答案 1 :(得分:1)

if ttcs:
            return sum([ttc.rank for ttc in ttcs])/len(ttcs)
        return 0

这可以由db查询替换。 https://docs.djangoproject.com/en/dev/topics/db/aggregation/

类似的东西:

ttcs.Aggregate(Sum('rank'))["sum__rank"]