Laravel Eloquent查询与集合优化:订单统计查询优化诉求
优化订单统计查询方案
直接用一次数据库聚合查询替代三次全量数据拉取,大幅提升性能,代码如下:
public function index(Order $order) { // 一次查询获取按年份分组的所有统计数据 $orderStats = Order::selectRaw( "YEAR(created_at) as year, SUM(total) as total_amount, SUM(CASE WHEN payment_confirmed = 1 THEN total ELSE 0 END) as paid_amount, SUM(CASE WHEN payment_confirmed = 0 THEN total ELSE 0 END) as unpaid_amount" ) ->groupBy('year') ->orderBy('year') ->get() ->keyBy('year'); // 整理成视图需要的三个数组格式 $orders = $orderStats->map(fn($stat) => $stat->total_amount)->toArray(); $paid_orders = $orderStats->map(fn($stat) => $stat->paid_amount)->toArray(); $unpaid_orders = $orderStats->map(fn($stat) => $stat->unpaid_amount)->toArray(); return view('orders.index', compact('orders', 'unpaid_orders', 'paid_orders')); }
核心优化点:
- 减少查询次数:从三次全表查询缩减为一次聚合查询,降低数据库IO和连接开销
- 数据库层面处理聚合:把分组、求和操作交给数据库完成,避免将全量订单数据加载到PHP内存中处理,数据量越大性能提升越明显
- 精简逻辑:通过
CASE WHEN语句在一次查询中同时计算总金额、已支付金额、未支付金额,无需多次过滤数据 - 日期处理优化:直接用数据库函数
YEAR(created_at)提取年份,避免在PHP中逐个处理日期格式
注:原代码中paid_orders的分组逻辑存在冗余判断(已过滤payment_confirmed=1的订单,却仍判断payment_confirmed == false),优化后的代码按原逻辑默认使用订单创建年份分组,若实际业务需按支付年份统计,可将YEAR(created_at)替换为YEAR(paid_at)(需确保模型有paid_at字段)。
内容的提问来源于stack exchange,提问作者McRui
相关产品推荐
相关产品推荐

