我正在尝试提高我的Django应用程序的性能,以使其运行更加流畅,这是改进我当前运行状态的第一次迭代的一部分。在进行性能分析时,我注意到我在几个页面上执行大量SQL查询。
例如,仪表板页面可以轻松地执行250多个SQL查询。进一步的调查使我注意到了views.py
中的以下代码段:
for project in projects:
for historicaldata in project.historical_data_for_n_months_ago(i):
for key in ('hours', 'expenses'):
history_data[key] = history_data[key] + getattr(historicaldata, key)
models.py
文件中的相关功能:
def historical_data_for_n_months_ago(self, n=1):
n_year, n_month = n_months_ago(n)
try:
return self.historicaldata_set.filter(year=n_year, month=n_month)
except HistoricalData.DoesNotExist:
return []
如您所见,这将导致对列表中的每个项目执行大量查询。最初,这种设置方式是将功能集中在模型级别,并在整个应用程序中引入便利功能。
如何减少在加载此页面时正在执行的查询数量?我当时正在考虑删除说服功能,而只是在视图中使用select_related()
,但是,为了筛选给定年份和月份的记录,它仍然需要大量查询。
非常感谢!
编辑,根据要求,提供有关相关模型的更多信息。
项目
class Project(models.Model):
name = models.CharField(max_length=200)
status = models.IntegerField(choices=PROJECT_STATUS_CHOICES, default=1)
last_updated = models.DateTimeField(default=datetime.datetime.now)
total_hours = models.DecimalField(default=0, max_digits=10, decimal_places=2)
total_expenses = models.DecimalField(default=0, max_digits=10, decimal_places=2)
def __str__(self):
return "{i.name}".format(i=self)
def historical_data_for_n_months_ago(self, n=1):
n_year, n_month = n_months_ago(n)
try:
return self.historicaldata_set.filter(year=n_year, month=n_month)
except HistoricalData.DoesNotExist:
return []
HistoricalData
class HistoricalData(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
year = models.IntegerField()
month = models.IntegerField()
hours = models.DecimalField(max_digits=10, decimal_places=2, default=0)
expenses = models.DecimalField(max_digits=10, decimal_places=2, default=0)
def __str__(self):
return "Historical data {i.month}/{i.year} for {i.person} ({i.project})".format(i=self)
答案 0 :(得分:0)
我不认为遍历查询集永远不是一个好主意。因此,如果您能找到其他方法,那就更好了。如果您可以详细说明视图功能以及应该执行的功能,那么我可以进一步提供帮助。
如果您要一个项目的所有history_data条目(反向相关),则需要使用prefetch_related。由于您想要与该项目相关的历史数据的特定部分,因此需要将其与Prefetch一起使用。
from django.db.models import Prefetch
Project.objects.prefetch_related(
Prefetch(
'historicaldata_set',
queryset=HistoricalData.objects.filter(year=n_year, month=n_month)
)
)
此后,您应该在Django模板中循环浏览此数据集(如果正在使用该模板)。您还可以将其传递给drf-serializer,这也可以完成您的工作:)