1

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

我写了以下查询来查找某个年龄段人的通话时间:

    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()

谢谢

4

2 回答 2

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
于 2013-07-26T02:12:43.720 回答
3

像这样的语句card_list=[Demo.objects.filter(age_group=age)[i].card_no for i in range(popn)]将生成popn单独的查询和数据库命中。-loop中的查询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 为您提供了一整套新功能,不仅可以更轻松地使用模型,还可以通过JOIN在 SQL 查询中使用子句来加快许多查询。因此,以您为例:

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

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

通过这两项更改,您的查询(包括对不同 age_group 的循环)可以更改为超快的一次性查询,为您提供每个 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 对象,并计算所有持续时间字段的平均值 - 所有这些都在一个查询中。

于 2013-07-26T13:01:15.873 回答