加速django嵌套循环时间序列

时间:2015-05-09 15:22:02

标签: python django performance datetime optimization

我正在开发一个名为OpenREM的基于django的开源项目(http://demo.openrem.org/openrem/http://openrem.org)。

要计算其中一个图表的数据,我正在执行一系列查询,以获取一周中每天24小时内每个项目的数量。该数据用于在演示站点的CT页面上绘制每个工作日的研究饼图,并深入研究当天每小时的研究:

studiesPerHourInWeekdays = [[0 for x in range(24)] for x in range(7)]
for day in range(7):
    studyTimesOnThisWeekday = f.qs.filter(study_date__week_day=day+1).values('study_time')
    if studyTimesOnThisWeekday:
        for hour in range(24):
            try:
                studiesPerHourInWeekdays[day][hour] = studyTimesOnThisWeekday.filter(study_time__gte = str(hour)+':00').filter(study_time__lte = str(hour)+':59').values('study_time').count()
            except:
                studiesPerHourInWeekdays[day][hour] = 0

在生产系统上运行需要一些时间。我认为第二个FOR循环可以通过使用qsstats-magic time_series删除,聚合时间超过几小时。遗憾的是,数据库中没有合适的日期时间对象可用于此目的。

有谁知道如何将“study_date”datetime.date对象和“study_time”datetime.time对象组合成一个datetime.datetime对象,以便能够按小时运行qsstats-magic time_series?

谢谢,

大卫

1 个答案:

答案 0 :(得分:1)

如果你可以(虽然你似乎无法满足你的情况),最好更改数据库架构以反映你正在制作的查询类型。具有此信息的日期时间字段,某种类型的外键设置等

您可能已经知道,但对您的问题的实际答案是您希望通过extra() call使用底层数据库工具。也许这样的事情*如果你正在使用postgres:

date_hour_set = f.qs.extra(
    select={
        'date_hour': "study_date + interval '1h' * date_part('hour', study_time)",
        'date_hour_count': "count(study_date + interval '1h' * date_part('hour', study_time))"
    }).values('date_hour', 'date_hour_count').distinct()

它将为您提供日期时间(仅限小时)的查询集及其关联的事件计数。由于Django's lagging TimeField support,手写SQL将为您提供最简单的选项,并且可能也是最高性能的选项。

*注意我不定期编写SQL并且很懒,所以有更简洁的方法来处理它。

如果你真的需要数据库可移植并且仍然无法编辑架构,你可以将Django聚合的功能叠加在一起,这些功能可能有点复杂:

from django.db.models import Value, Count, ExpressionWrapper, CharField
from django.db.models.functions import Substr, Concat

hour_counts = f.qs.annotate(hour=Concat(Substr('study_time', 1, 2), Value(':00:00')))
date_hour_pairs = hour_counts.annotate(
        date_hour=ExpressionWrapper(Concat('study_date', 'hour'),
        output_field=CharField())).values('study_date', 'hour', 'date_hour')
date_hour_counts = date_hour_pairs.annotate(count=Count('date_hour')).distinct()

它应该为您提供一组带有datetime.time对象的dicts,用于' hour&#39 ;,您开始使用的datetime.date用于' study_date',一个连续的字符串版本的' date_hour'下的日期和时间,然后是' count'下的所有重要(日期,小时)计数。