我在Django中设置了一个复杂的数据库模型,我必须根据过滤数据进行一些计算。我有一个Test
对象,一个TestAttempt
对象和一个UserProfile
对象(外键返回测试,外键返回用户配置文件)。我在TestAttempt
上运行一种方法来计算测试分数(基于用户提供的多个选项与每个测试相关的正确答案进行比较)。然后我在Test
上运行的另一种方法,根据每个关联的TestAttempt
来计算平均测试分数。但有时我只想要基于相关{{1}提供的子集的平均值。 1}}与一组特定的TestAttempt
相关联。因此,不要以这种方式计算特定测试的平均测试分数:
UserProfiles
然后平均这些值。 我这样做一个查询:
[x.score() for x in self.test_attempts.all()]
其中[x.score() for x in self.test_attempts.filter(profile__id__in=user_id_list).all()]
是UserProfile id的特定子集,我希望以列表的形式找到平均测试分数。我的问题是这样的:如果user_id_list
确实是user_id_list
的整个集合(因此过滤器将返回与UserProfile
相同的内容),并且大部分时间都是如此,是否需要检查这种情况,如果是这样,根本不执行过滤器?或__in查找是否足够有效,即使self.test_attempts.all()
包含所有用户,运行过滤器也会更有效。另外,我是否需要担心生成的test_attempts distinct()?或者他们不可能用我的queryset结构重复复制?
编辑:对于有兴趣查看原始SQL查询的任何人,如果没有过滤器,它看起来像这样:
user_id_list
以及过滤器:
SELECT "mc_grades_testattempt"."id", "mc_grades_testattempt"."date",
"mc_grades_testattempt"."test_id", "mc_grades_testattempt"."student_id" FROM
"mc_grades_testattempt" WHERE "mc_grades_testattempt"."test_id" = 1
请注意,数组(1,2,3)只是一个例子
答案 0 :(得分:2)
根据我对文档的理解,所有查询都是在实际使用之前构建的。因此,例如,test_attempts.all()
生成SQL代码一次,当您执行查询时,实际通过执行.count()
,for t in test_attempts.all():
等操作来获取数据,它会在数据库上运行查询如果使用get(),则返回Queryset对象或仅返回Object。考虑到这一点,对数据库的调用次数将完全相同,而实际调用将是不同的。正如您在编辑后的帖子中所显示的那样,原始查询是不同的,但在Django访问数据之前,它们都以相同的方式生成。从Django的角度来看,它们都将以相同的方式创建,然后在数据库上执行。在我看来,最好不要测试all()情况,因为你必须运行两个查询来确定。我相信您应该使用您拥有的代码运行并跳过检查all()方案,您将其描述为最常见的情况。大多数现代数据库引擎以这样的方式运行查询:添加的连接不会妨碍性能指标,因为它们无论如何都以最佳顺序处理查询。
答案 1 :(得分:2)
简短回答是 - 基准。在不同情况下测试并测量负载。这将是最好的答案。
这里不能有重复。
检查两个情况真的是个问题吗?这是hypotetic代码:
def average_score(self, user_id_list=None):
qset = self.test_attempts.all()
if user_id_list is not None:
qset = qset.filter(profile__id__in=user_id_list)
scores = [x.score() for x in qset]
# and compute the average
我不知道score
方法做了什么,但你不能计算数据库级别的平均值吗?它会给你带来更多值得注意的性能提升。
不要忘记缓存。
答案 2 :(得分:2)
使用Annotation而不是循环查询集,这会为user_id_list中的每个项创建一个新的数据库命中,并在python中执行平均值。
ms = MyModel.objects.annotate(Avg('some_field'))
ms[0].avg__some_field # prints the average for that instance
将返回查询集,其中平均可用作查询集中对象的属性。使用ORM可能需要您对外键关系进行结构更改,哪个模型包含哪些数据以便使注释方便。如果有必要,这种重新排序将产生有益的副作用(数据喜欢以某种方式生活),所以这是一个很好的练习。