You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化Django中多过滤与排除语句的QuerySet性能咨询

优化方案:提升查询效率

你的这段代码确实有优化空间,主要可以从减少查询次数、优化数据库过滤逻辑这两个方向入手,下面是具体的实现和说明:

优化后的代码实现

from django.db.models import Q, Exists, OuterRef

def get_queryset(self):
    current_user = self.request.user
    # 定义拉黑用户的子查询:匹配当前用户拉黑的、且与Profile关联的用户
    blocked_subquery = Blocked.objects.filter(
        user=current_user,
        blocked_user=OuterRef('user')
    )
    # 定义已挥手用户的子查询:匹配当前用户已挥手的、且与Profile关联的用户
    waved_subquery = UserWave.objects.filter(
        user=current_user,
        waved_user=OuterRef('user')
    )
    
    # 一次过滤完成所有条件:排除自己、未被拉黑、未挥手过的用户
    return Profile.objects.filter(
        ~Q(user=current_user),
        ~Exists(blocked_subquery),
        ~Exists(waved_subquery)
    )

关键优化点说明

  • 用Exists子查询替代values+user__in:原代码会先执行两次独立查询(获取拉黑用户ID列表、已挥手用户ID列表),再传给Profile的exclude,总共3次SQL查询。改用Exists后,只会执行1次Profile查询,两个子查询会作为WHERE条件的一部分在数据库层面完成过滤,减少了数据传输和查询开销。
  • 合并过滤条件:把多次exclude合并成一个filter操作,用~Q()和~Exists()组合条件,让SQL语句更简洁,数据库能生成更高效的执行计划。
  • 直接使用用户对象关联:避免手动提取user.id,Django会自动处理外键关联逻辑,代码更简洁且不易出错。

额外性能优化建议:添加数据库索引

因为你的查询频繁基于user、blocked_user、waved_user这些字段过滤,给这些字段添加索引能大幅提升查询速度:

修改Blocked模型

class Blocked(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_thats_blocking", db_index=True)
    blocked_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="blocked_user", db_index=True)
    
    class Meta:
        # 添加联合索引,针对同时过滤user和blocked_user的场景
        indexes = [
            models.Index(fields=['user', 'blocked_user']),
        ]

修改UserWave模型

class UserWave(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="current_user", db_index=True)
    waved_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="waved_user", db_index=True)
    
    class Meta:
        # 添加联合索引,针对同时过滤user和waved_user的场景
        indexes = [
            models.Index(fields=['user', 'waved_user']),
        ]

Profile模型(可选)

OneToOneField默认会创建索引,但可以显式声明确保:

class Profile(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.OneToOneField(User, on_delete=models.CASCADE, db_index=True)
    bio = models.TextField(null=True, blank=True)

内容的提问来源于stack exchange,提问作者rafaelHTML

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:35:26