Python的counter()函数太慢了

时间:2018-06-07 02:45:30

标签: python django python-2.7

我正在使用Django REST框架,并且我在使用Counter()函数的行中遇到了速度问题的帖子API。

@api_view(["POST"])
def calculate_stuff(request):
  t1 = time.time()
  machine_type = request.data['machine_type']
  machine_nos = Machine.objects.filter(machine_type=machine_type).values_list('machine_no', flat=True)
  query = Performance.objects.filter(Q(power=100) | Q(power=192),machine_no__in=machine_nos,
                ).values_list("machine_no", "power")
  t2 = time.time()
  print t2 - t1 # is around 0.2 seconds 
  count_192_100 = Counter(query) 
  t3 = time.time()
  print t3 - t2 # is around 1.3 seconds

模型是这样的:

class Machine(models.Model):
  machine_type = models.CharField(null=True, max_length=10)
  machine_no = models.IntegerField(null=True)
  store_code = models.IntegerField(null=True)
  created = models.DateTimeField(auto_now_add=True)
  updated = models.DateTimeField(auto_now = True)
class Performance(models.Model):
  machine_no = models.IntegerField(null=True)
  power = models.IntegerField(null=True)
  store_code = models.IntegerField(null=True) 
  created = models.DateTimeField(auto_now_add=True)
  updated = models.DateTimeField(auto_now=True)

这个项目正在生产中,由于某些原因,两个模型之间没有使用Foreignkey。我想在这里实现的是First:从某个machine_type的“Machine”模型中获取machine_no。第二:我想得到每台机器没有多少次。在“性能”模型中,功率= 100,功率= 192。 附加信息:我使用的是Django 1.11,python 2.7.10,postgresql。

3 个答案:

答案 0 :(得分:2)

我实际上并不认为这是你的聚合计数器很慢,但你的查询设置评估即你的数据访问。请参阅Django ORM QuerySets是所谓的“懒惰”。它们可以被操纵但是评估(实际获取数据)被推迟到某些触发执行上下文。以下是概述此内容的文档: https://docs.djangoproject.com/en/2.0/ref/models/querysets/#when-querysets-are-evaluated

  

评估QuerySet时¶

     

在内部,可以构造,过滤,切片和查询QuerySet   通常在没有实际访问数据库的情况下传递。没有   数据库活动实际发生,直到您做一些评估   查询集。

因此,由于你的timeit构造,它看起来只是瓶颈是你的聚合计数器,但它可能不是。这可能是对查询集的评估。

有一些优化dB访问的策略,这里概述了它们: https://docs.djangoproject.com/en/2.0/topics/db/optimization/

不知道多一点,我们不能更具体。如果你不介意分享你的dB模型以及它实际获得的数据的一些细节,我很乐意提供帮助。

您可以使用本文中概述的方法之一对强制评估运行timeit,例如在查询集上使用内置列表(),并在计数器构造函数确定之前进行此操作。

答案 1 :(得分:1)

反击并不是所有的时间。 实际上运行查询并获取结果是所有时间。在迭代QuerySet之前,查询不会运行,这在您调用Counter时会发生。

不要调用Counter,而是考虑让数据库为你做计数。

答案 2 :(得分:0)

 query = Performance.objects.filter(Q(power=100) | 
    Q(power=192),machine_no__in=machine_nos,
                ).values_list("machine_no", "power")
 count_192_100 = Counter(query) 

将数据库中的任何行的实际对象拉下来,对它们进行反序列化,然后使用散列对它们执行唯一的计数。相反,请使用您的数据库来获取它的优点 -

count_192_100 = Performance.objects.filter(Q(power=100) | 
    Q(power=192),machine_no__in=machine_nos,
                ).values_list("machine_no", "power").count()

.count()基本上是select COUNT(*) from...

当然我应该提到这与查询不同的QUITE - 计数器使用散列来计算唯一值!如果您可能在该表中有重复的行,则需要select COUNT(DISTINCT *) FROM ...,您可以使用

count_192_100 = Performance.objects.filter(Q(power=100) | 
    Q(power=192),machine_no__in=machine_nos,
                ).values_list("machine_no", "power").distinct().count()