Как вернуть количество записей в день за каждый день года без дорогостоящего запроса в цикле? - PullRequest
0 голосов
/ 13 июня 2019

В таблице базы данных мы находим записи с filepaths, сотрудником, который обработал файл (ы), и отметкой времени, когда файл был обработан.Таблица «Журнал» содержит всего несколько тысяч записей на одного сотрудника.На одного сотрудника в основном приходится несколько записей в день с отметкой времени (хотя это не уникальная отметка времени).Я хотел бы извлечь список кортежей, содержащих дату и количество записей в таблице, сделанных на эту дату.

Код, который я предоставил, работает, но работает ОЧЕНЬ медленно.Время расчета 2200 секунд для 2300 записей нелепо.Я сузил проблему до строки "logs_per_day = (query.select (). Where (fn.date (cls.datetime) == checkday) .count ())" в цикле for.Я понимаю, что делать много запросов в цикле, вероятно, не очень хорошо.Кроме того, преобразование объекта datetime в дату, вероятно, тоже не помогает ... Кто-нибудь может подсказать мне лучший способ, как это сделать?

import datetime
import os

from peewee import *

db = SqliteDatabase('logs.db')
# db = SqliteDatabase(':memory:')
now = datetime.datetime.now()

class BaseModel(Model):

    class Meta:
        database = db


class Log(BaseModel):

    log_ID = AutoField()
    datetime = DateTimeField()
    letter = CharField()
    disk_path = CharField()
    ftp_path = CharField()
    out = BooleanField()
    employee = CharField(null=True)

    class Meta:
        table_name = 'log'

    @classmethod
    def get_histo_data(cls, employee="Some Dude", year=None):
        """returns a list with sublists (datetime object, integer)"""
        if not year: # if no year was provided the query return all entries from the employee
            query = cls.select().where(cls.employee == employee).order_by(cls.datetime)
            print(employee, len(query), " entries")

            firstday = query.order_by(cls.datetime).get().datetime.date()
            lastday = query.order_by(cls.datetime.desc()).get().datetime.date()

        else: # returns all entries in the given year
            query = (cls
                        .select()
                        .where(cls.employee == employee, cls.datetime.year == year)
                        .order_by(cls.datetime)
                    )
            print("{} has {} entries in the year {}".format(employee, len(query), year))

            firstday = datetime.date(year, 1, 1)
            lastday = datetime.date(year, 12, 31)

        print("first day sent: ", firstday)
        print("last day sent: ", lastday)

        daydelta = (lastday-firstday).days
        sendList = []

        for i in range(daydelta+1):   ### FIXME: This is extremely slow!!!
            checkday = firstday + datetime.timedelta(days=i)
            logs_per_day = (query
                                .select()
                                .where(fn.date(cls.datetime) == checkday)
                                .count()
                                )

            # print(checkday, "*** logs that day: ", logs_per_day)
            sendList.append([checkday, logs_per_day])

        return sendList

def initialize():
    db.connection()
    db.create_tables([Log], safe=True)
    db.close()

if __name__ == '__main__':
    initialize()

    Log.get_histo_data(employee="Mr Someone", year=2018)

Вывод должен быть примерно таким: "[(2018-11-12, 157), (2018-11-13, 12), (2018-11-14, 0) ...]

1 Ответ

0 голосов
/ 13 июня 2019

Нашел сам:

def get_histo_data(cls, employee="Some dude", year=None):
    """returns a list of tuples (datetime object, integer)"""
    if not year: # if no year was provided the query return all entries from the employee
        query = cls.select().where(cls.employee == employee).order_by(cls.datetime)
        print(employee, len(query), " entries")

        firstday = query.order_by(cls.datetime).get().datetime.date()
        lastday = query.order_by(cls.datetime.desc()).get().datetime.date()

    else: # returns all entries in the given year
        query = cls.get_query_by_year(employee, year)
        print("{} has {} entries in the year {}".format(employee, len(query), year))

        firstday = datetime.date(year, 1, 1)
        lastday = datetime.date(year, 12, 31)

    ### count the entries
    logDict = dict()
    for record in query:
        date = record.datetime.date()
        if date not in logDict:
            logDict[date] = 1
        else:
            logDict[date] += 1
    ### fill the null days
    daydelta = (lastday-firstday).days
    for i in range(daydelta+1):
        checkday = firstday + datetime.timedelta(days=i)
        if checkday not in logDict:
            logDict[checkday] = 0
        else:
            continue

    return list(sorted(logDict.items()))
...