我的一个观点是,一个特定的查询会对数据库造成很大的冲击。Scout-apm将其识别为一个可能的n+1查询。我不确定这是问题所在,但这确实是一个问题。
我的原始代码是:
models.py
class Grade(models.Model):
score = models.CharField(max_length=4, blank=True)
testing = models.ForeignKey(Testing, on_delete=models.CASCADE)
student = models.ForeignKey(Student, on_delete=models.CASCADE)
classroom = models.ForeignKey(Purpose, on_delete=models.CASCADE)
time_created = models.DateField(
auto_now=False, auto_now_add=False, default=timezone.now)
Class Testing(models.Model):
name = models.CharField(max_length=20, blank=True)
omit = models.BooleanField(default=False)
Class Classroom(models.Model):
name = models.CharField(max_length=20, blank=True)
views.py
def allgrades(request, student_id):
classrooms = Classroom.objects.all()
for c in classrooms:
q = Grade.objects.filter(
student=student_id, classroom=c.id, testing__omit="False").order_by('-time_created')
if q.exists():
if len(q) < 3:
qn = q.first()
else:
....
令人不快的查询来自if q.exists():
和qn = q.first()
。我不知道这是否福尔斯n + 1的范畴,但是如果我去掉if q.exists():
和qn = q.first()
,查询的数量从大约1300减少到大约400
我需要这些语句的功能。因为我正在使用q
,所以我需要检查它是否存在。正如代码所示,我可能只想包含最新的对象。
有没有更便宜的方法来解决这个问题?
1条答案
按热度按时间1l5u6lss1#
在每个classroom循环中,你都要进行额外的调用。第一个是.exists(),它可以低成本地查看那里是否有东西,但是如果有,你需要调用它,就会变得有点多余,因为检索实际记录是另一个调用(所以最多是2 * num_classrooms)。
如果预取所有内容,则根本不需要进行许多额外调用: