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

Laravel 9中使用with()引发多查询,是否应改用join?

问题解答

首先纠正你现有代码的两个问题:

  • with()方法的参数写法错误,应该把嵌套关联用点语法串联,或者放在同一个数组结构里;
  • 筛选"John"的条件应该直接写在Person的查询上,你写的['person']关联完全没必要——因为本身就是查询Person模型。

回到你的核心问题:要不要改用join?这取决于你的使用场景,下面是两种方案的对比和代码示例:

方案一:优化Eloquent预加载(推荐用于需要完整模型实例的场景)

Laravel的预加载是解决N+1查询的标准方案,你之前的错误写法导致了多余查询,正确的嵌套预加载会用批量whereIn来获取关联数据,效率并不低:

// 正确写法:一次性获取John及其关联的街道、城市、州、国家
$person = Person::where('name', 'John')
    ->with('street.city.state.country')
    ->first();

这种写法会执行5次批量查询:

  1. 查询名为John的Person
  2. 根据Person的street_id批量查询对应的Street
  3. 根据Street的city_id批量查询对应的City
  4. 根据City的state_id批量查询对应的State
  5. 根据State的country_id批量查询对应的Country

虽然是多次查询,但都是批量操作,比你原来错误的写法高效很多,而且返回的是完整的Eloquent模型实例,后续可以直接访问关联属性(比如$person->street->city->state->country)或者调用模型方法。

方案二:使用Join(推荐用于只需要少量字段的场景)

如果你的需求仅仅是获取John的基础信息和所属国家的部分字段(比如国家名称),用join可以把所有查询合并为一次,效率更高,但返回的是扁平结果,没有完整的模型关联结构:

// 用Join一次性查询,注意给重复字段加别名避免冲突
$person = Person::select(
        'persons.*',
        'countries.name as country_name',
        'countries.id as country_id'
    )
    ->join('streets', 'streets.id', '=', 'persons.street_id')
    ->join('cities', 'cities.id', '=', 'streets.city_id')
    ->join('states', 'states.id', '=', 'cities.state_id')
    ->join('countries', 'countries.id', '=', 'states.country_id')
    ->where('persons.name', 'John')
    ->first();

如果存在Person未关联Street的极端情况,需要把join改成leftJoin,避免数据被过滤掉。

总结

  • 若后续需要操作关联模型(比如修改国家信息、调用Country模型的方法),选优化后的预加载;
  • 若只需要扁平的字段数据,不需要完整模型,选Join更高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:10:28