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

Django多对多查询性能问题:900万条数据查询耗时超15分钟

问题根源
  • Django默认自动生成的多对多中间表索引结构不符合查询场景:默认生成的中间表仅会创建(follower_id, hashtag_id)的联合唯一约束/索引,如果你执行的是从Hashtag反向查询关联的Follower的场景,该联合索引无法生效,会触发中间表全表扫描,900万条数据的全表扫描耗时自然会极高。
  • ORM查询写法不规范:大概率存在N+1查询问题,比如遍历Follower查询集时每次访问hashtags属性都触发一次单独的数据库查询,或者未使用预加载接口加载关联数据,导致数据库查询次数随结果集线性增长。
  • 过滤条件未命中索引:如果查询时用到了hashtags__name这类跨表过滤条件,未命中索引也会触发主表全表扫描。
优化方案

1. 索引优先优化

手动定义多对多中间表,按需创建索引,替换Django自动生成的默认中间表:

# 新增中间表模型
class FollowerHashtag(models.Model):
    follower = models.ForeignKey("Follower", on_delete=models.CASCADE)
    hashtag = models.ForeignKey("instagram_data.Hashtag", on_delete=models.CASCADE)

    class Meta:
        unique_together = ("follower", "hashtag")
        indexes = [
            # 适配从Follower查关联Hashtag的场景
            models.Index(fields=["follower", "hashtag"]),
            # 适配从Hashtag反向查关联Follower的场景
            models.Index(fields=["hashtag", "follower"]),
        ]

# 修改原Follower模型的多对多字段配置
class Follower(models.Model):
    hashtags = models.ManyToManyField(
        "instagram_data.Hashtag", 
        through=FollowerHashtag,
        verbose_name=_("hashtags_name")
    )

执行migrate生效后,双向的关联查询都可以命中索引,避免全表扫描。

2. ORM查询写法优化

  • 多对多关联查询必须使用prefetch_related预加载关联数据,彻底避免N+1问题:
    # 示例:查询符合条件的Follower及关联的Hashtag
    follower_list = Follower.objects.filter(你的过滤条件).prefetch_related("hashtags")
    
  • 仅需要部分字段时,用only/values减少数据加载量,比如只需要Hashtag的name字段时:
    from django.db.models import Prefetch
    follower_list = Follower.objects.filter(你的过滤条件).prefetch_related(
        Prefetch("hashtags", queryset=Hashtag.objects.only("name"))
    )
    
  • 反向查询仅需要关联ID时,直接查中间表即可,无需关联主表:
    # 示例:查询某Hashtag关联的所有Follower ID
    follower_ids = FollowerHashtag.objects.filter(hashtag_id=目标hashtag的id).values_list("follower_id", flat=True)
    

3. 大数据量进阶优化(适配后续2亿条数据规模)

  • 高频查询场景增加缓存层:把经常查询的关联关系(比如热门Hashtag对应的Follower列表)存入Redis,设置合理的过期时间,避免每次请求都查数据库。
  • 模糊搜索场景引入全文检索引擎:如果有按hashtag名称模糊搜索的需求,把Hashtag的name字段同步到Elasticsearch,先通过ES拿到符合条件的Hashtag ID,再查中间表取关联数据,比数据库的LIKE模糊查询性能提升10倍以上。
  • 水平分表:数据量达到亿级后,按follower_id或者hashtag_id对中间表做水平拆分,降低单表数据量,避免单表性能瓶颈。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 16:54:08