【发布时间】:2021-08-26 20:53:52
【问题描述】:
我正在处理 django 中一个相当慢的查询,该查询需要显示按多个组的成员身份过滤的用户。结果列表只需要包含唯一用户,这对于小数字来说很好,但是在返回处理大型查询集时就变成了一个很大的问题。不幸的是,在这个阶段修改数据库结构并不可行,因为这是一个拥有大量活跃用户群的实时产品。
当前设置外观的基本示例:
class Group( models.Model ):
name = models.CharField(max_length=50)
class User( models.Model ):
name= models.CharField( max_length=100)
groups = models.ManyToManyField( Group, related_name='members' )
class UserDisplayModule( models.Model ):
display_groups = models.ManyToManyField( Group, related_name='display_modules' )
一个视图通常会加载一个模块,然后通过分配的组列出与该模块关联的所有用户,例如:
class UserModuleMembers( ModelViewSet ):
def get_queryset(self):
user_module = self.get_module()
return User.objects.filter(groups__in=module.display_groups.all()).distinct()[offset:offset+limit]
实际模型的列数要大一些,但关系确实如上。一个用户可能是多个组的成员,并且可以将多个组分配给一个模块,因此此处需要 distinct() 子句,因为如果单个用户在附加到一个模块。然后对生成的查询集进行分页。
上述内容对于小型应用程序来说效果很好,但我们正在快速发展,现在正在处理一个视图可能包含 100,000 多个用户的情况。即使有分页,这个查询也需要几秒钟才能返回。如果没有 distinct 子句,它会快很多,但由于多组的事情,我们会得到重复的记录。
底层数据库是 postgres,我尝试使用.distinct( 'name', 'id' ) 来限制考虑为“唯一性”的列,但这并没有明显的区别。
如果有人可以提出一种替代方法,我真的很想听听!
【问题讨论】:
-
我更关心
groups__in=module.display_groups.all() -
为什么不
User.objects.filter(groups__display_modules=module).distinct()。这会产生一些简单的连接。 -
噢……这是一个有趣的想法,我一定会尝试一下
-
虽然原始方法只会产生子查询,所以我认为就连接而言应该没问题?
-
好的,是的,速度快了一点,谢谢——这似乎指向了正确的方向
标签: python django postgresql django-rest-framework orm