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

Laravel数据库查询优化:按比例拉取直连及互关好友动态性能优化咨询

代码优化方案

原有代码存在3个核心问题:一是多次全量加载关联数据到内存做过滤,IO开销高;二是使用union查询会触发临时表排序,额外增加性能损耗;三是未实现业务要求的70%直连好友、10%互关好友的比例控制,结果占比不可控。可按以下方案优化:

  • 第一步先补充基础索引,从底层降低查询开销:
    • following表加联合索引(follower_id, following_id),覆盖关注关系查询的过滤条件
    • posts表加联合索引(profile_id, created_at),覆盖按发布者筛选、按时间排序的查询需求
  • 第二步重构查询逻辑,去掉不必要的中间数据加载,拆分查询替代union:
function feedUpdate($perPage = 20) {
    $currentUserId = Auth::id();
    // 子查询获取当前用户关注的id列表,不用全量加载到内存
    $followingIdQuery = Following::where('follower_id', $currentUserId)->select('following_id');
    
    // 按70%比例取直连好友动态,默认按发布时间倒序,可根据业务调整排序规则
    $friendPostCount = ceil($perPage * 0.7);
    $friendPosts = Post::whereIn('profile_id', $followingIdQuery)
        ->orderByDesc('created_at')
        ->limit($friendPostCount)
        ->get();
    
    // 按10%比例取互关/好友的好友动态
    $mutualPostCount = ceil($perPage * 0.1);
    $mutualPosts = collect();
    if ($mutualPostCount > 0) {
        // 先按共同关注数排序取top互关候选,避免全表随机性能差
        $mutualIdList = Following::whereIn('follower_id', $followingIdQuery)
            ->whereNotIn('following_id', $followingIdQuery) // 排除已经关注的用户,避免内容重复
            ->where('following_id', '!=', $currentUserId) // 排除自己
            ->groupBy('following_id')
            ->orderByRaw('COUNT(*) DESC')
            ->limit($mutualPostCount * 5) // 多取部分候选再随机,保证内容多样性
            ->pluck('following_id');
        
        $mutualPosts = Post::whereIn('profile_id', $mutualIdList)
            ->inRandomOrder()
            ->limit($mutualPostCount)
            ->get();
    }
    
    // 合并结果,不足perPage的部分可补充热门动态等内容凑数,可根据业务调整
    $posts = $friendPosts->merge($mutualPosts);
    
    // 可选:合并后统一按发布时间排序,保证时间线合理性
    return new FeedResourceCollection($posts);
}

优化后查询次数从4次降到2-3次,且所有查询都走索引,不会加载全量好友数据到内存,性能提升非常明显,同时完全符合业务比例要求。

多表关联查询最佳实践
  • 索引优先:所有where、join、group by、order by用到的字段都要配置索引,多条件过滤场景优先使用联合索引,遵循最左匹配原则,避免全表扫描
  • 避免中间数据冗余:不要将全表/全量关联数据加载到应用内存再做过滤、聚合操作,尽量通过SQL子查询、聚合函数在数据库层面完成计算,减少数据IO开销
  • 慎用高开销SQL操作:union、inRandomOrder()、distinct、大表join这类操作开销很高,非必要不使用,必须使用的话要先把结果集过滤到最小范围再执行
  • 避免N+1查询:Laravel场景下使用with()、withCount()预加载关联数据,禁止在循环中执行关联查询
  • 适当做字段冗余:Feed流这类读多写少的场景,可以把发布者昵称、头像等常用字段冗余到post表,不用每次查询都关联用户表,减少join操作
  • 热点数据缓存:高频访问的feed列表、关注关系列表可以设置几分钟的缓存,不用每次请求都查库,大幅降低数据库压力

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 12:06:04