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

Eloquent关联查询如何快速计算价格总和?withSum适配方案

Eloquent 关联条件累加优化方案

原实现存在N+1查询缺陷:首次查询拉取B模型集合后,遍历每条B数据都会单独发起一次关联查询,数据量上升后性能会明显下降,可根据业务场景选择以下两种更高效的实现:


方案1:单SQL直接聚合(性能最优)

如果不需要复用查询到的B模型集合,可直接通过子查询在数据库层完成累加计算,无需加载模型到内存、无循环逻辑,仅需一次数据库请求:

$total = B::where('user_id', $user)
    ->selectRaw('COALESCE(SUM((
        SELECT counter
        FROM 关联表名 // 替换为b_by_a关联对应的实际数据表名
        WHERE 关联表名.b_id = b.id // 替换为b_by_a关联定义的外键匹配规则
        AND 你的筛选条件 // 对应传入的$condition,建议使用参数绑定避免SQL注入
        LIMIT 1
    )), 0) as total')
    ->value('total');

如果$condition是键值对数组格式的筛选条件,可以通过查询构造器的绑定方法安全传参,避免手动拼接SQL的风险。


方案2:带条件预加载(需复用B集合时使用)

如果后续逻辑需要使用查询到的B模型集合,可通过动态条件预加载关联数据,仅需2次数据库请求即可完成数据拉取,后续在集合层面完成累加,不会产生额外查询:

// 第一次查询:拉取符合条件的B集合
// 第二次查询:一次性拉取所有B模型匹配$condition的关联数据
$bCollection = B::where('user_id', $user)
    ->with(['b_by_a' => function ($query) use ($condition) {
        $query->where($condition)->select(['id', 'b_id', 'counter']); // 仅查询需要的字段,降低内存占用
    }])
    ->get();

// 集合内存中完成累加,无额外IO开销
$total = $bCollection->sum(function ($b) {
    return $b->b_by_a->first()?->counter ?? 0;
});

关于withSum适配说明

你之前使用withSum无法适配业务,通常是没有传入闭包定义关联的动态筛选条件。如果你的业务需求是累加每个B模型下所有符合$condition的关联数据的counter总和(而非取第一条关联数据的counter),可以直接用带条件约束的withSum实现:

$total = B::where('user_id', $user)
    ->withSum(['b_by_a' => fn($q) => $q->where($condition)], 'counter')
    ->get()
    ->sum('b_by_a_sum_counter');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 18:31:28