Django查询优化

时间:2013-07-26 01:43:11

标签: database django django-models

我目前正在从事电信分析项目和新手查询优化工作。要在浏览器中显示结果,需要完整分钟,而只需访问45,000条记录。你能否建议减少展示结果的时间。

我写了以下查询来查找 a 年龄组人员的通话时间:

    sigma=0
    popn=len(Demo.objects.filter(age_group=age))
    card_list=[Demo.objects.filter(age_group=age)[i].card_no
                for i in range(popn)]
    for card in card_list:
        dic=Fact_table.objects.filter(card_no=card.aggregate(Sum('duration'))
        sigma+=dic['duration__sum']
    avgDur=sigma/popn

以上代码在for循环内迭代年龄组。

模型如下:

class Demo(models.Model):
    card_no=models.CharField(max_length=20,primary_key=True)
    gender=models.IntegerField()
    age=models.IntegerField()
    age_group=models.IntegerField()



class Fact_table(models.Model):
    pri_key=models.BigIntegerField(primary_key=True)
    card_no=models.CharField(max_length=20)
    duration=models.IntegerField()
    time_8bit=models.CharField(max_length=8)
    time_of_day=models.IntegerField()
    isBusinessHr=models.IntegerField()
    Day_of_week=models.IntegerField()
    Day=models.IntegerField()

由于

2 个答案:

答案 0 :(得分:4)

试试:

sigma=0
demo_by_age = Demo.objects.filter(age_group=age);

popn=demo_by_age.count() #One

card_list = demo_by_age.values_list('card_no', flat=True) # Two

dic = Fact_table.objects.filter(card_no__in=card_list).aggregate(Sum('duration') #Three
sigma = dic['duration__sum']

avgDur=sigma/popn

答案 1 :(得分:3)

card_list=[Demo.objects.filter(age_group=age)[i].card_no for i in range(popn)]之类的语句将生成popn单独的查询和数据库命中。 for - 循环中的查询也将在数据库中popn次。作为一般规则,您应该尽量减少使用的查询量,并且只应选择所需的记录。

通过对代码进行一些调整,可以在一个查询中完成。

  • 通常不需要手动指定primary_key,除了一些非常特殊的情况外,最好不要定义任何一个。 Django自动添加一个索引的自动增量主键字段。如果您需要将card_no字段作为唯一字段,并且需要根据此字段查找行,请使用以下命令:

    class Demo(models.Model):
        card_no = models.SlugField(max_length=20, unique=True)
        ...
    

    SlugField会自动向列中添加数据库索引,实际上该字段的选择与主键的选择速度一样快。这仍然允许其他方式来访问表格,例如外键(我将在下一点解释),使用Django指定的(稍微)更快的整数字段,并将简化Django中模型的使用。

  • 如果您需要将对象与另一个表中的对象相关联,请使用models.ForeignKey。 Django为您提供了一整套新功能,不仅可以更轻松地使用模型,还可以通过在SQL查询中使用JOIN子句来加快查询速度。所以对你来说:

    class Fact_table(models.Model):
        card = models.ForeignKey(Demo, related_name='facts')
        ...
    

    related_name字段允许您通过在Django中使用instance.facts来访问与Demo实例相关的所有Fact_table对象。 (见https://docs.djangoproject.com/en/dev/ref/models/fields/#module-django.db.models.fields.related

通过这两项更改,您的查询(包括不同age_groups上的循环)可以更改为一个超快速的单击查询,为您提供每个age_group的平均呼叫持续时间:

age_groups = Demo.objects.values('age_group').annotate(duration_avg=Avg('facts__duration'))
for group in age_groups:
    print "Age group: %s - Average duration: %s" % group['age_group'], group['duration_avg']

.values('age_group')仅从Demo的数据库表中选择age_group字段。 .annotate(duration_avg=Avg('facts__duration'))values获取每个唯一的结果(因此每个唯一的age_group),并且对于每个唯一的结果,将获取与该age_group内的任何Demo对象相关的所有Fact_table对象,并计算所有持续时间字段的平均值 - 所有在一个查询中。