【问题标题】:django query aggregate function is slow?django查询聚合函数很慢?
【发布时间】:2017-09-14 19:54:01
【问题描述】:

我正在使用 Django 来了解如何处理大型数据库。我使用包含名称、年龄、出生日期(dob)和身高的数据库。该数据库有大约 500000 个条目。我必须找到(1)同龄和(2)同年出生的人的平均身高。查询表中的聚合函数大约需要 10s。是平常还是我错过了什么?

年龄:

age = [i[0] for i in Data.objects.values_list('age').distinct()]
ht = []
for each in age:
    aggr = Data.objects.filter(age=each).aggregate(ag_ht=Avg('height')
    ht.append(aggr)

来自dob,

age = [i[0].year for i in Data.objects.values_list('dob').distinct()]
for each in age:
    aggr = Data.objects.filter(dob__contains=each).aggregate(ag_ht=Avg(‌​'height')
    ht.append(aggr)

必须从 dob 中提取年份。它是 SQLite,我不能使用 __year (join)。

【问题讨论】:

  • 在第二种情况下如何过滤?
  • 我用的是同一个结构的filter。 for each in age: aggr = Data.objects.filter(dob__contains=each).aggregate(ag_ht=Avg('height') ht.append(aggr); ht.append(aggr)
  • 我会考虑你的情况

标签: django sqlite aggregate django-queryset


【解决方案1】:

要使这些查询高效,您必须在 agedob 列上输入 create indexes

使用covering indexes,即使用包含height 列的两列索引,您将获得额外的小幅加速。

【讨论】:

    【解决方案2】:

    带有时间比较循环和查询集版本的完整版

    import time
    from dd.models import Data
    from django.db.models import Avg
    from django.db.models.functions import ExtractYear
    

    年龄

    start = time.time()
    age = [i[0] for i in Data.objects.values_list('age').distinct()]
    ht = []
    
    for each in age:
        aggr = Data.objects.filter(age=each).aggregate(ag_ht=Avg('height'))
        ht.append(aggr)
    
    end = time.time()
    loop_time = end - start
    
    start = time.time()
    qs = Data.objects.values('age').annotate(ag_ht=Avg('height')).order_by('age')
    ht_qs = qs.values_list('age', 'ag_ht')
    end = time.time()
    qs_time = end - start
    
    print loop_time / qs_time
    

    对于出生年份,可以轻松重构您的版本(在年份中添加设置)

    start = time.time()
    years = set([i[0].year for i in Data.objects.values_list('dob').distinct()])
    ht_year_loop = []
    for each in years:
        aggr = Data.objects.filter(dob__contains=each).aggregate(ag_ht=Avg('height'))
        ht_year_loop.append((each, aggr.get('ag_ht')))
    
    end = time.time()
    loop_time = end - start
    
    start = time.time()
    qs = Data.objects.annotate(dob_year=ExtractYear('dob')).values('dob_year').annotate(ag_ht=Avg('height'))
    ht_qs = qs.values_list('dob_year', 'ag_ht')
    end = time.time()
    qs_time = end - start
    
    print loop_time / qs_time
    

    【讨论】:

    • 这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review
    • @BradGilbert 为什么不呢?如果我是正确的,这个查询必须更快并给出相同的值。
    • 是的,它确实适用于年龄。但我希望有一个适用于年龄和年份的通用代码。还有一个出生日期(dob)字段,我想通过从 dob 字段中提取年份来进行相同的聚合。所以为此我打算只修改age = set([i.year for i in Data.objects.values_list('age').distinct()]),但它很慢。它是 SQLite,所以 __year (join) 无法完成。
    • 你能在你的问题中写下你真正需要的东西吗?可能有人可以给出完整而好的答案。
    • 这是从审核队列生成的自动评论。我对这个话题一无所知,只是看起来它没有回答这个问题。如果它更长并且实际上解释了为什么它应该起作用,我就不会投票关闭它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多