Laravel模型查询中如何关联WITH子查询并优化性能?
在Laravel中关联CTE优化关联查询性能
实现思路
借助Laravel的withExpression方法定义CTE,将其关联到主查询或关联关系中,替代性能低下的子查询方案。
具体实现步骤
关联CTE到offers关联关系
先通过withExpression注册你的CTE,再在offers关联的闭包内通过join关联CTE,获取对应lead和offer的最近发送时间:$leads = Lead::withExpression('last_sent_at', function ($query) { $query->select('offer_id', 'lead_id', DB::raw('max(created_at) as sent_at')) ->from('offer_history') ->groupBy('offer_id', 'lead_id'); }) ->with([ // 保留原有其他关联 'offers' => function ($query) { $query->join('last_sent_at', function ($join) { $join->on('offers.id', '=', 'last_sent_at.offer_id') ->on('last_sent_at.lead_id', '=', DB::raw('leads.id')); }) ->select('offers.*', 'last_sent_at.sent_at'); } ]) ->filters() ->get();将最近发送时间挂载到Lead模型
若希望把最近发送时间直接作为Lead的属性,可通过left join关联CTE:$leads = Lead::withExpression('last_sent_at', function ($query) { $query->select('lead_id', DB::raw('max(created_at) as latest_sent_at')) ->from('offer_history') ->groupBy('lead_id'); }) ->leftJoin('last_sent_at', 'leads.id', '=', 'last_sent_at.lead_id') ->with([/* 原有关联 */]) ->filters() ->select('leads.*', 'last_sent_at.latest_sent_at') ->get();
关键说明
withExpression是Laravel 8及以上版本支持的方法,能高效定义CTE,在大数据量场景下性能优于子查询。- 关联时需确保
lead_id和offer_id的关联条件准确,避免数据匹配错误。 - 若
offers是通过offer_history建立的多对多关联,可调整关联逻辑,直接在中间表关联中引入CTE。
内容的提问来源于stack exchange,提问作者Константин Джанов
相关产品推荐
相关产品推荐

