我的模型有几百万个对象。每个对象代表公司拨打/接听的电话。
为简化起见,我们假设这个模型Call有这些字段:
calldate,context,channel。
我的目标是了解每月每个小时内拨打和接听的平均电话数(按小时加载)。问题是:我需要分别为 port1 和 port2 找到它。
到目前为止,我的代码工作正常,除了大约需要1分钟才能给出4个月的结果,而且效率非常低。
我做了一些简单的分析,发现扩展占用了大约99%的处理时间:
queryset = Call.objects.filter(calldate__gte='SOME_DATE')
port1, port2 = [],[]
port1.extend(queryset.filter(context__icontains="e1-1"))
port2.extend(queryset.filter(context__icontains="e1-2"))
channels_in_port1 = ["Port/%d-2" % x for x in range(1,32)]
channels_in_port2 = ["Port/%d-2" % x for x in range(32,63)]
for i in channels_in_port1:
port1.extend(queryset.filter(channel__icontains=i))
for i in channels_in_port2:
port2.extend(queryset.filter(channel__icontains=i))
port1和port2现在有大约150k个对象组合在一起。
只要我打电话给 port1 和 port2 ,我就很高兴。其余代码基本上是针对 port1 和 port2 的循环,它们总结并根据小时/天/月取得平均值。琐碎的东西。
我试图通过使用itertools.chain并链接查询集来避免使用任何“扩展”。然而,这使得处理时间转移到我做琐碎for循环的部分,以便按小时计算负载。
任何替代方案?更好的方法来过滤查询集?
非常感谢!!
答案 0 :(得分:0)
您是否考虑过使用django的聚合函数? http://docs.djangoproject.com/en/dev/topics/db/aggregation/
答案 1 :(得分:0)
我认为你的问题是第二组扩展,即for循环中的那些,而不是第一组。 (在任何情况下,第一个都是完全没必要的:不是在前面定义一个空列表并扩展它,你可以port1 = list(queryset.filter(context__icontains="e1-1"))
。)
无论如何,总结一下我认为你要做的事情:你希望获得特定日期的所有Call
个对象,分为两个块,具体取决于channel
的值:一个包含它的地方值为0到31,值为32到62之间。
看起来你只需要两个查询就可以做到这一点,而根本没有任何扩展:
port1 = queryset.filter(channel__range=["Port/1-2", "Port/31-2"])
port2 = queryset.filter(channel__range=["Port/1-32", "Port/31-62"])
这不符合您的要求吗?
编辑以回复评论,但这只是您可以扩展或连接的两个查询。您的代码发布的问题在于您正在执行 31 查询并扩展每个端口的操作,这必然是昂贵的。如果你只做一个,加上一个扩展/ concat,那将会便宜得多。