首页 > 解决方案 > 过滤多个集合中的成员资格时如何避免 distinct()?

问题描述

我正在努力处理 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' )限制考虑为“唯一性”的列,但这没有明显的区别。

如果有人可以建议一种替代方法,我真的很想听听!

标签: pythondjangopostgresqldjango-rest-frameworkorm

解决方案


我更关心groups__in=module.display_groups.all()小组部分。虽然子查询可以像简单的 JOIN 一样快,但通常很多数据库都在处理子查询。

可能有帮助的是在一个条件下用JOINs 来写这个。这也将使查询更简单,这通常意味着数据库可以更好地优化查询。

我们可以过滤:

User.objects.filter(groups__display_modules=module).distinct()

推荐阅读