Database Django查询优化

Database Django查询优化,database,django,django-models,Database,Django,Django Models,我目前从事电信分析项目和查询优化新手。要在浏览器中显示结果,需要完整的分钟,而只需访问45000条记录。你能建议一下缩短展示结果时间的方法吗 我编写了以下查询以查找某个年龄组的人的通话持续时间: 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

我目前从事电信分析项目和查询优化新手。要在浏览器中显示结果,需要完整的分钟,而只需访问45000条记录。你能建议一下缩短展示结果时间的方法吗

我编写了以下查询以查找某个年龄组的人的通话持续时间:

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

试试看:

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
试试看:

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

card\u list=[Demo.objects.filter(age\u group=age)[i].card\u no for i in range(popn)]
这样的语句将生成
popn
单独的查询和数据库点击。
for
-循环中的查询也会命中数据库
popn
次。一般来说,您应该尽量减少使用的查询量,并且只选择需要的记录

只需对代码进行一些调整,就可以在一个查询中完成

  • 通常不需要手动指定主键,在所有情况下,除了一些非常特殊的情况外,最好不要定义任何主键。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')
        ...
    
    相关的\u name字段允许您使用Django中的
    instance.facts
    访问与演示实例相关的所有事实表对象。(见附件)

通过这两个更改,您的查询(包括不同年龄组的循环)可以更改为一个快速的一键查询,为您提供每个年龄组呼叫的平均持续时间:

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\u group')
仅从演示的数据库表中选择age\u group字段
.annotate(duration\u avg=avg('facts\u duration'))
值中获取每个唯一的结果(因此每个唯一的年龄组),对于每个唯一的结果,将获取与该年龄组中的任何演示对象相关的所有事实表对象,并计算所有持续时间字段的平均值-全部在单个查询中

card\u list=[Demo.objects.filter(age\u group=age)[i].card\u no for i in range(popn)]
这样的语句将生成
popn
单独的查询和数据库点击。
for
-循环中的查询也会命中数据库
popn
次。一般来说,您应该尽量减少使用的查询量,并且只选择需要的记录

只需对代码进行一些调整,就可以在一个查询中完成

  • 通常不需要手动指定主键,在所有情况下,除了一些非常特殊的情况外,最好不要定义任何主键。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')
        ...
    
    相关的\u name字段允许您使用Django中的
    instance.facts
    访问与演示实例相关的所有事实表对象。(见附件)

通过这两个更改,您的查询(包括不同年龄组的循环)可以更改为一个快速的一键查询,为您提供每个年龄组呼叫的平均持续时间:

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\u group')
仅从演示的数据库表中选择age\u group字段
.annotate(duration\u avg=avg('facts\u duration'))
值中获取每个唯一的结果(因此每个唯一的年龄组),对于每个唯一的结果,将获取与该年龄组中的任何演示对象相关的所有事实表对象,并计算所有持续时间字段的平均值-全部在单个查询中

感谢你的耐心。我从未在几行操作代码中见过如此多的反模式。应该是:
card\u list=Demo.objects.filter(age\u group=age)。values\u list('card\u no',flat=True)
?第二个查询(
card\u list=demo\u by\u age.values\u list('card\u no',flat=True)#两个
)实际上从未执行,而是在执行第三个查询时用作嵌套的select语句。+1请耐心等待。我从未在几行操作代码中见过如此多的反模式。应该是:
card\u list=Demo.objects.filter(age\u group=age)。values\u list('card\u no',flat=True)
?在您的第二个查询(
card\u list=demo\u by\u age.values\u list(
card\u list=demo\u by\u age.values\u list')中缺少一个引号