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

Laravel中whereIn()为何比关联查询更快?如何优化关联查询?

Laravel关联查询vs whereIn查询性能优化问题解答

首先要明确:你用的两种写法本质上返回的结果集不同——关联查询是获取客户模型集合,同时预加载每个客户对应的托运单;而whereIn写法是直接获取所有符合条件的托运单,不关联客户模型。如果你的需求只是拿到所有托运单,whereIn写法本身就更轻量化,速度快是合理的。但如果需要同时保留客户与托运单的对应关系,关联查询的性能是可以优化的,下面分析可能的问题和解决方案:

关联查询变慢的可能原因

  1. 不必要的字段查询:关联查询默认会拉取客户表和托运单表的所有字段,如果表中存在大字段(比如text类型、JSON字段),会大幅增加数据传输和内存消耗。
  2. 关联定义存在额外约束:如果Customer模型的consignments关联默认添加了orderBy、where等额外条件(比如return $this->hasMany(Consignment::class)->orderBy('created_at')),而这些条件对应的字段没有建立索引,会导致预加载的查询变慢。
  3. 索引未正确命中:虽然你说加了索引,但需要确认:
    • 托运单表的customer_id字段是否有单独的普通索引;
    • 如果关联查询有额外过滤条件(比如只查已完成的托运单),是否建立了customer_id + 过滤字段的复合索引。
  4. 客户数据量过大:如果where('id','>',1)返回的客户数量极多,即使预加载了托运单,处理大量客户模型集合也会带来额外的内存开销。

关联查询的优化方案

1. 只选择需要的字段

通过select()指定要查询的字段,减少数据传输和内存占用:

// 只查询客户的必要字段,同时指定托运单的必要字段
$customers = Customer::select('id', 'name')
    ->with(['consignments' => function ($query) {
        $query->select('id', 'customer_id', 'tracking_no', 'created_at');
    }])
    ->where('id', '>', 1)
    ->get();

2. 检查并优化关联定义

如果关联有默认的排序或过滤条件,确保对应字段有索引:
比如关联定义是:

public function consignments()
{
    return $this->hasMany(Consignment::class)->orderBy('created_at', 'desc');
}

那需要给consignments表的created_at字段建立索引,或者建立customer_id + created_at的复合索引,提升排序和查询效率。

3. 对比SQL查询语句

开启Laravel的查询日志,查看关联预加载生成的SQL和手动whereIn的SQL是否有差异,排查是否有额外的低效逻辑:

DB::enableQueryLog();

// 执行关联查询
$customers = Customer::with('consignments')->where('id','>',1)->get();

// 打印查询日志
dd(DB::getQueryLog());

对比日志中的SQL,看预加载的托运单查询是否和手动whereIn的SQL一致,是否有多余的条件导致索引未命中。

4. 替代方案:分组获取托运单

如果你的核心需求是获取客户对应的托运单,不需要完整的客户模型,可以直接查询托运单并按customer_id分组,兼顾性能和对应关系:

$customerIds = Customer::where('id', '>', 1)->pluck('id');
$consignmentsByCustomer = Consignment::whereIn('customer_id', $customerIds)
    ->get()
    ->groupBy('customer_id');

这种写法既保留了客户与托运单的对应关系,又避免了处理大量客户模型的开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 18:50:25