python - 需要快速更新 Django 模型与其他两个模型之间的差异

标签 python django

我正在通过提供年初至今统计数据的 API 填充我的数据库,并且我将每天多次从该 API 中提取数据。使用年初至今的统计数据,我需要生成每月和每周的统计数据。我目前正在尝试通过从月底的统计数据中减去月初的统计数据并将其保存在单独的模型中来实现这一点,但是这个过程花费的时间太长了,我需要它更快.

我的模型看起来像这样:

class Stats(models.Model):
    date = models.DateField(default=timezone.now) # Date pulled from API
    customer_id = models.IntegerField(default=0) # Simplified for this example
    a = models.IntegerField(default=0)
    b = models.IntegerField(default=0)
    c = models.IntegerField(default=0)
    d = models.IntegerField(default=0)

class Leaderboard(models.Model):
    duration = models.CharField(max_length=7, default="YEARLY") # "MONTHLY", "WEEKLY"
    customer_id = models.IntegerField(default=0)
    start_stats = models.ForeignKey(Stats, related_name="start_stats") # Stats from the start of the Year/Month/Week
    end_stats = models.ForeignKey(Stats, related_name="end_stats") # Stats from the end of the Year/Month/Week
    needs_update = models.BooleanField(default=False) # set to True only if the end_stats changed (likely when a new pull happened)
    a = models.IntegerField(default=0)
    b = models.IntegerField(default=0)
    c = models.IntegerField(default=0)
    d = models.IntegerField(default=0)
    e = models.IntegerField(default=0) # A value computed based on a-d, used to sort Leaderboards

我以为我可以使用 Leaderboard.objects.filter(needs_update=True).update(a=F("end_stats__a")-F("start_stats__a"), ...),但这给了我一个错误“此查询中不允许加入字段引用”

我目前正在遍历 QuerySet Leaderboard.objects.filter(needs_update=True),执行减法操作并保存(全部使用 @transaction.atomic ),但是以这种方式处理的约 380,000 条测试记录只用了一个多小时,所以我怀疑这种方式对于我需要的东西来说太慢了。


如果不同的格式可以帮助这个排行榜更新更快,我可以改变我存储数据的方式(也许在提取数据时做减法并保存每日增量?),但我觉得我一直在赶时间想什么就做什么,而不知道在这种情况下我应该做什么。非常感谢此时的任何反馈。

最佳答案

经过大量修改,我想我找到了一种适用于这种情况的方法。我的测试样本比以前小(84,600 条记录),但它在 8 秒内完成 - 大约每秒 10,575 条记录(与我之前测试的大约每秒 6,300 条记录相比)。

可能有一种方法可以进一步完善它,但这是我正在做的:


    from django.db.models import F, Subquery, OuterRef

    # Get the latest versions of the stats
    Leaderboard.objects.filter(needs_update=True).update(
        a=Subquery(Stats.objects.filter(pk=OuterRef('end_stats')).values('a')[:1]),
        b=Subquery(Stats.objects.filter(pk=OuterRef('end_stats')).values('b')[:1]),
        c=Subquery(Stats.objects.filter(pk=OuterRef('end_stats')).values('c')[:1]),
        d=Subquery(Stats.objects.filter(pk=OuterRef('end_stats')).values('d')[:1])
    )

    # Subtract the earliest versions of the stats
    Leaderboard.objects.filter(needs_update=True).update(
        a=F('a') - Subquery(Stats.objects.filter(pk=OuterRef('start_stats')).values('a')[:1]),
        b=F('b') - Subquery(Stats.objects.filter(pk=OuterRef('start_stats')).values('b')[:1]),
        c=F('c') - Subquery(Stats.objects.filter(pk=OuterRef('start_stats')).values('c')[:1]),
        d=F('d') - Subquery(Stats.objects.filter(pk=OuterRef('start_stats')).values('d')[:1])
    )

    # Calculate stats that require earlier stats.
    Leaderboard.objects.filter(needs_update=True).update(
        e=F('a') + F('b') * F('c') / F('d'),
        needs_update=False
    )

我觉得应该有一种方法每次更新只使用一个子查询,这应该会进一步提高速度。

关于python - 需要快速更新 Django 模型与其他两个模型之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53789518/

相关文章:

python - 表单提交未收到多个 html 选择

django - 将 django south 与一组不同的数据库凭据一起使用

python - 具体爆列

c++ - 从 C++ 调用时指定 Python 模块的目录

python - 网络开发RAD Web 应用程序开发框架。在最短时间内(Yii vs. Django)

python - 使用特定版本的 Python 创建 Windows Python virtualenv

python - 是否可以不收集标记测试?

python - PyCharm 没有正确执行 `django-manage.py`

python - 如何检查 request.GET var 是否为 None?

python - Django 用户注销无法重定向主页