如何用Eloquent优化商品维度聚合查询?将6次慢查询合并为单次
问题
我有一个类似$products = Product::query()->where(...)...的查询,需要为双范围滑块获取商品的尺寸极值,当前写法如下:
$dimensionLimits = [ 'width' => [ 'min' => $products->min('width'), 'max' => $products->max('width') ], 'height' => [ 'min' => $products->min('height'), 'max' => $products->max('height') ], 'depth' => [ 'min' => $products->min('depth'), 'max' => $products->max('depth') ], ];
该写法会产生6次相对较慢的查询,我想知道能否不使用原生SQL,而是用Eloquent生成的查询将其优化为单次查询?
优化方案
当然可以用Eloquent的聚合查询一次性搞定,只需要一次数据库请求就能获取所有维度的极值,不用跑6次查询。给你两种实现方式:
方法一:用selectRaw快速实现
这种写法最简洁,直接在查询里指定要计算的所有聚合值:
$stats = $products->selectRaw( 'MIN(width) as width_min, MAX(width) as width_max, MIN(height) as height_min, MAX(height) as height_max, MIN(depth) as depth_min, MAX(depth) as depth_max' )->first(); $dimensionLimits = [ 'width' => [ 'min' => $stats->width_min, 'max' => $stats->width_max ], 'height' => [ 'min' => $stats->height_min, 'max' => $stats->height_max ], 'depth' => [ 'min' => $stats->depth_min, 'max' => $stats->depth_max ], ];
方法二:纯Eloquent链式调用(无原生SQL片段)
如果不想写原生SQL的字段部分,可以用addSelect配合子查询的方式实现:
$stats = $products->addSelect([ 'width_min' => Product::query()->selectRaw('MIN(width)')->whereColumn('products.id', 'products.id'), 'width_max' => Product::query()->selectRaw('MAX(width)')->whereColumn('products.id', 'products.id'), 'height_min' => Product::query()->selectRaw('MIN(height)')->whereColumn('products.id', 'products.id'), 'height_max' => Product::query()->selectRaw('MAX(height)')->whereColumn('products.id', 'products.id'), 'depth_min' => Product::query()->selectRaw('MIN(depth)')->whereColumn('products.id', 'products.id'), 'depth_max' => Product::query()->selectRaw('MAX(depth)')->whereColumn('products.id', 'products.id'), ])->first(); // 整理成需要的数组结构 $dimensionLimits = [ 'width' => [ 'min' => $stats->width_min, 'max' => $stats->width_max ], 'height' => [ 'min' => $stats->height_min, 'max' => $stats->height_max ], 'depth' => [ 'min' => $stats->depth_min, 'max' => $stats->depth_max ], ];
两种方法都能实现单次查询,第一种效率更高、代码更短,推荐优先使用。另外要注意,你之前构建的$products查询实例里的where条件会被自动继承,聚合计算只会针对过滤后的商品数据。
内容的提问来源于stack exchange,提问作者inf3rno
相关产品推荐
相关产品推荐

