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

Laravel:单次关联查询筛选拥有福特汽车的Person用户

解决Laravel中筛选关联模型并避免N+1查询的问题

嘿,你遇到的这个N+1查询问题很常见,我来帮你搞定它!

首先,你当前的代码用whereHas确实能筛选出所有拥有福特汽车的用户,但循环里调用$person->cars()->get()会导致每遍历一个用户就执行一次数据库查询——这就是典型的N+1问题(1次查用户,N次查每个用户的汽车)。

优化方案1:约束预加载(推荐,代码清晰且性能优秀)

我们可以用with()方法来预加载符合条件的关联汽车,同时保留whereHas的筛选逻辑,这样整个过程只会执行2次数据库查询(1次查符合条件的用户,1次批量查这些用户的福特汽车),完美避免N+1。

修改后的代码如下:

$persons = Person::whereHas('cars', function ($query) {
    $query->where('mark', 'ford');
})->with(['cars' => function ($query) {
    // 只预加载该用户的福特汽车
    $query->where('mark', 'ford');
}])->get();

// 遍历的时候直接访问属性,不用再调用get()
foreach ($persons as $person) {
    foreach($person->cars as $car) {
        print $person->name . " has a " . $car->mark . "\n";
    }
}

优化方案2:使用JOIN实现单次查询(适合仅需用户信息的场景)

如果你确实需要单次数据库查询完成,也可以用join来关联两张表,不过这种方式如果用户有多辆福特车,会返回重复的用户记录,需要用distinct()去重:

// 仅获取拥有福特车的用户信息(不含汽车详情)
$persons = Person::select('persons.*')
    ->join('cars', 'persons.id', '=', 'cars.person_id')
    ->where('cars.mark', 'ford')
    ->distinct()
    ->get();

但要注意,这种方式没法直接拿到用户对应的福特汽车详情,如果需要同时获取用户和汽车信息,还是第一种约束预加载的方案更实用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:02:33