Laravel 8 Eloquent关联过滤:匹配日期的关联数据查询优化
解决方案
1. 定义带日期匹配的专属关联关系
把日期匹配逻辑直接封装到关联方法里,既能避免重复写闭包,也能让Laravel更高效处理关联查询:
public function websiteRevenueMatchingDate() { return $this->hasMany(WebsiteRevenue::class, 'website_id', 'website_id') ->whereColumn('website_revenue.date', 'website_shares_dynamic.date'); } public function websiteMeasureMatchingDate() { return $this->hasMany(WebsiteMeasure::class, 'website_id', 'website_id') ->whereColumn('website_measure.date', 'website_shares_dynamic.date'); }
查询时直接调用这个关联即可:
$queryResult = WebsiteShareDynamic::with(['websiteRevenueMatchingDate', 'websiteMeasureMatchingDate']) ->whereIn('website_shares_dynamic.id', $maxWSD) ->orderBy('website_shares_dynamic.date', 'DESC') ->get();
2. 用子查询预加载减少连接开销
如果直接的表连接性能还是差,可以换成子查询预加载的方式,避免大表关联的开销:
$queryResult = WebsiteShareDynamic::query() ->whereIn('website_shares_dynamic.id', $maxWSD) ->orderBy('website_shares_dynamic.date', 'DESC') ->with([ 'websiteRevenue' => function ($query) { $query->whereColumn('website_revenue.date', function ($sub) { $sub->select('date') ->from('website_shares_dynamic') ->whereColumn('website_shares_dynamic.id', 'website_revenue.website_id'); }); }, 'websiteMeasure' => function ($query) { $query->whereColumn('website_measure.date', function ($sub) { $sub->select('date') ->from('website_shares_dynamic') ->whereColumn('website_shares_dynamic.id', 'website_measure.website_id'); }); } ]) ->get();
3. 必须加索引(性能提升核心)
不管用哪种查询方式,索引缺失都是性能慢的核心原因,给以下字段创建联合索引:
website_revenue表:(website_id, date)website_measure表:(website_id, date)website_shares_dynamic表:(id, date)(如果id是主键已有索引,至少给date单独加索引)
创建索引的SQL示例:
CREATE INDEX idx_website_revenue_website_date ON website_revenue(website_id, date); CREATE INDEX idx_website_measure_website_date ON website_measure(website_id, date);
为什么whereHas没效果?
whereHas的作用是筛选主模型(只保留存在符合条件关联的主模型记录),而不是过滤预加载的关联数据。你需要的是预加载时只返回匹配date的关联记录,所以whereHas不适用,必须用with的闭包来约束关联模型的查询范围。
内容的提问来源于stack exchange,提问作者InfY Pir
相关产品推荐
相关产品推荐

