Laravel 8中从HasMany关联仅取子模型数据及求和方法
Laravel关联查询优化:大表下获取最新价格总和的问题与解决
表关联与基础查询实现
我有两个MySQL表,通过HasMany/belongsTo关联,关联代码如下:
public function Products() { return $this->hasMany(Prices::class, 'product_id'); } public function Prices() { return $this->belongsTo(Products::class); }
通过以下关联方法可获取每个产品的最新价格:
public function LatestPrices() { return $this->hasOne(Prices::class, 'product_id')->orderBy('date','desc'); }
在控制器中可通过foreach循环访问数据:
$values = Products::with('LatestPrices')->get(); foreach ($values as $value) { // 业务逻辑 echo $value->LatestPrices->price; }
问题
- 能否仅获取价格数据,得到仅包含价格的数组?
- 能否不通过foreach循环,直接计算所有产品最新价格的总和?
解决方案(针对200万+行的大表场景)
我是Laravel新手,习惯用原生PHP+MySQL,原本想把原生内连接查询转成Eloquent实现,但在200万+行的数据表中,Eloquent查询速度很慢。
原生SQL查询(性能基准)
原生查询语句如下:
SELECT SUM(a.sells_value) AS value FROM prices a INNER JOIN products b ON a.product_id = b.id INNER JOIN ( SELECT product_id, MAX(prices.date) as Max_date FROM prices GROUP BY product_id ) c ON a.product_id = c.product_id AND a.date = c.Max_date AND ((b.merchand = 1 and b.product_tag = "Something") or (b.merchand = 1 and b.product_tag = "Something"));
他人提供的Eloquent方案(性能不佳)
有人提供了Eloquent实现方案,虽然能得到正确结果,但耗时是foreach循环的4倍:
Products::where([['merchand','=',1],['product_tag','=', 'Something']]) ->orWhere([['merchand','=',1],['product_tag','=', 'Something']]) ->with('LatestPrices') ->get() ->pluck('LatestPrices.prices') ->sum();
最终最优方案:使用DB::select执行原生SQL
最终测试发现,用DB::select执行原生SQL的速度远快于foreach循环和普通Eloquent方案:
DB::select('SELECT SUM(a.sells_value) AS value FROM prices a INNER JOIN products b ON a.product_id = b.id INNER JOIN ( SELECT product_id, MAX(prices.date) as Max_date FROM prices GROUP BY product_id ) c ON a.product_id = c.product_id AND a.date = c.Max_date AND ((b.merchand = 1 and b.product_tag = "Something") or (b.merchand = 1 and b.product_tag = "Something"))');
内容的提问来源于stack exchange,提问作者Mohammed
相关产品推荐
相关产品推荐

