gpt4 book ai didi

python - 减少 Django 数据库查询

转载 作者:太空狗 更新时间:2023-10-29 21:18:14 25 4
gpt4 key购买 nike

我有非常大的数据集并且还在不断增长,我需要创建许多过滤器,但它很快就会失控,我希望有人能帮助我将一些查询合并到一个调用中。下面是我的观点的开始。

调用 #1 - for 循环以显示所有结果的表格

traffic = Traffic.objects.all()

调用 #2 - 组合聚合总和查询

totals = Traffic.objects.aggregate(Sum('sessions'), Sum('new_users'), Sum('reminder'), Sum('campaigns'), Sum('new_sales'), Sum('sales_renewals'))
total_sessions = totals.get('sessions__sum')
total_new_users = totals.get('new_users__sum')
total_reminder = totals.get('reminder__sum')
total_campaigns = totals.get('campaigns__sum')
total_new_sales = totals.get('new_sales__sum')
total_sales_renewals = totals.get('sales_renewals__sum')

调用 #3、#4、#5、#6 等等... - 按月份和星期几过滤数据库

total_sessions_2014_m = Traffic.objects.filter(created__year='2014', created__week_day=2).aggregate(Sum('sessions'))

total_sessions_2014_m = Traffic.objects.filter(created__year='2014', created__week_day=3).aggregate(Sum('sessions'))

total_sessions_2014_m = Traffic.objects.filter(created__year='2014', created__week_day=4).aggregate(Sum('sessions'))

total_sessions_2014_m = Traffic.objects.filter(created__year='2014', created__week_day=5).aggregate(Sum('sessions'))

total_sessions_2014_m = Traffic.objects.filter(created__year='2014', created__week_day=6).aggregate(Sum('sessions'))

问题是,我需要再创建几十个过滤器,因为我有 3 年的数据,每列有多个数据点,我们需要计算总和。

问题:

  1. 我可以将调用 #1 合并到调用 #2 中吗
  2. 我可以使用 Call #2 来查询 call#3 的总和,这样我就不必调用数据库中的所有对象来过滤它,然后再这样做几十次吗?

如您所见,这很快就会失控。任何帮助将不胜感激。谢谢。

更新添加流量模型

class Timestamp(models.Model):
created = models.DateField()

class Meta:
abstract = True


class Traffic(Timestamp):
sessions = models.IntegerField(blank=True, null=True)
new_users = models.IntegerField(blank=True, null=True)
reminder = models.IntegerField(blank=True, null=True)
campaigns = models.IntegerField(blank=True, null=True)
new_sales = models.IntegerField(blank=True, null=True)
sales_renewals = models.IntegerField(blank=True, null=True)

# Meta and String
class Meta:
verbose_name = 'Traffic'
verbose_name_plural = 'Traffic Data'

def __str__(self):
return "%s" % self.created

最佳答案

有许多方法可以使用 Django ORM 优化数据库查询。像往常一样,Django documentation很棒并且有一个很好的列表。以下是查询优化的一些快速提示:

1) iterator()

如果您只访问一次queryset。因此,例如,您可以将其用作,

traffic = Traffic.objects.all()

for t in traffic.iterator():
...
...

2) db_index=True

在定义您的模型 的字段时。作为Django documentation说,

This is a number one priority, after you have determined fromprofiling what indexes should be added. Use Field.db_index orMeta.index_together to add these from Django. Consider adding indexesto fields that you frequently query using filter(), exclude(),order_by(), etc. as indexes may help to speed up lookups.

因此你可以修改你的模型,

class Traffic(Timestamp):
sessions = models.IntegerField(blank=True, null=True, db_index=True)
new_users = models.IntegerField(blank=True, null=True, db_index=True)
reminder = models.IntegerField(blank=True, null=True, db_index=True)
campaigns = models.IntegerField(blank=True, null=True, db_index=True)
new_sales = models.IntegerField(blank=True, null=True, db_index=True)

3) prefetch_related()select_related()

如果您在模型 中有关系,则可以选择使用prefetch_relatedselect_related。根据 Django documentation ,

select_related 通过创建一个 SQL join 并在 SELECT 语句中包含相关对象的字段来工作。为此,select_related 在同一数据库查询中获取相关对象。但是,为了避免通过连接“多”关系产生更大的结果集,select_related 仅限于单值关系 - 外键和一对一。

prefetch_related 另一方面,对每个进行单独查找关系,并在 Python 中进行“连接”。这允许它预取多对多和多对一对象,不能使用select_related,以及select_related支持的外键和一对一关系。

select_related 执行一个joinprefetch_related 执行两个单独的查询。使用这些,您可以将查询速度提高多达 30%。


4) Django Pagination

如果您的模板设计允许您在多个页面中显示结果,您可以使用Pagination


5) Querysets are Lazy

您还需要了解 Django 查询集是惰性的,这意味着它在使用/评估之前不会查询数据库。 Django 中的查询集表示数据库中的许多行,可以选择通过查询进行过滤。例如,

traffic = Traffic.objects.all()

上面的代码没有运行任何数据库查询。您可以采用 traffic 查询集并应用其他过滤器,或将其传递给函数,并且不会向数据库发送任何内容。这很好,因为查询数据库是显着降低 Web 应用程序速度的事情之一。要从数据库中获取数据,您需要遍历查询集:

for t in traffic.iterator():
print(t.sessions)

6) django-debug-toolbar

Django 调试工具栏是一组可配置的面板,显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息。这包括:

  • 请求计时器
  • SQL 查询,包括执行时间和 EXPLAIN 每个查询的链接

修改您的代码:(记住查询集是惰性的)

traffic = Traffic.objects.all()
totals = traffic.aggregate(Sum('sessions'), Sum('new_users'), Sum('reminder'), Sum('campaigns'), Sum('new_sales'), Sum('sales_renewals'))
total_sessions = totals.get('sessions__sum')
total_new_users = totals.get('new_users__sum')
total_reminder = totals.get('reminder__sum')
total_campaigns = totals.get('campaigns__sum')
total_new_sales = totals.get('new_sales__sum')
total_sales_renewals = totals.get('sales_renewals__sum')

t_2014 = traffic.filter(created__year='2014')
t_sessions_2014_wd2 = t_2014.filter(created__week_day=2).aggregate(Sum('sessions'))
...
...

对于模板中的调用#1 (for 循环以显示所有结果的表格):

{% for t in traffic.iterator %}
{{ t.sessions }}
...
...
{% endfor %}

关于python - 减少 Django 数据库查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36171506/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com