Счетчик Python () работает слишком медленно - PullRequest
0 голосов
/ 07 июня 2018

Я использую Django REST Framework, и есть пост API, с которым я сталкиваюсь с проблемой скорости в строке, где я использую функцию Counter ().

@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 не использовался между двумя моделями.Первое, чего я хочу достичь, это получить: machine_no из модели "Machine" определенного machine_type.Второе: я хочу узнать, сколько раз у каждой машины нет.имел мощность = 100 и мощность = 192 в модели «Performance».Дополнительная информация: я использую Django 1.11, python 2.7.10, postgresql.

Ответы [ 3 ]

0 голосов
/ 07 июня 2018

Я на самом деле не думаю, что это ваш совокупный счетчик, который медленен, но ваша оценка набора запросов, т.е. ваш доступ к данным.Посмотрите, что Django ORM QuerySets - это то, что известно как «ленивый».Их можно манипулировать, но оценка (фактически получение данных) откладывается до некоторого запуска контекста выполнения.Вот документы, описывающие это: https://docs.djangoproject.com/en/2.0/ref/models/querysets/#when-querysets-are-evaluated

Когда оцениваются QuerySets¶

Внутренне, QuerySet может быть создан, отфильтрован, нарезан и, как правило, передан без фактического попадания вбаза данных.На самом деле никаких действий с базой данных не происходит, пока вы не сделаете что-то для оценки набора запросов.

Так что из-за вашей конструкции timeit это выглядит так, будто узким местом является ваш совокупный счетчик, но, скорее всего, нет.Вероятно, это оценка набора запросов.

Есть несколько тактик для оптимизации доступа к дБ, они изложены здесь: https://docs.djangoproject.com/en/2.0/topics/db/optimization/

Не зная немного больше, мы не можемболее конкретно.Если вы не против поделиться своей моделью дБ и некоторыми подробностями о том, сколько данных она на самом деле получает, я был бы рад помочь.

Вы можете запустить timeit для принудительной оценки одним из методов, описанных встатья, как использование встроенного list () в наборе запросов, и это должно произойти до того, как конструктор счетчика узнает наверняка.

0 голосов
/ 07 июня 2018
 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...

Конечно, я должен упомянуть, что это не делает совсем то же самое, чтоВаш запрос счетчик использует хеширование для подсчета уникальных значений!Если возможно, что у вас есть дублирующиеся строки в этой таблице, вы хотите 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()
0 голосов
/ 07 июня 2018

Счетчик не то, что занимает все это время. На самом деле выполнение запроса и получение результатов - вот что занимает все это время.Запрос не будет запущен, пока вы не выполните итерацию по QuerySet, что происходит, когда вы вызываете Counter.

Вместо вызова Counter, рассмотрите возможность подсчета за базу данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...