优化Laravel查询

时间:2020-07-04 06:52:57

标签: php laravel

我正在一个项目中,我需要以Excel格式导出产品销售报告。我正在使用Maatwebsite/Laravel-Excel

我有三个模型。

product.php

class products extends Model
{
    protected $table='products';
    public $timestamps = false;

    protected $fillable  = ['image', 'asin','price','strategy_id'];

    public function orderDetails()
    {
        return $this->hasMany(order_details::class, 'SKU', 'asin');
    }

}

orders.php

class orders extends Model
{
    protected $table = 'orders';
    public $timestamps = false;

    protected $fillable = ['id','date','quantity','totalAmount'];

    public function orderDetails()
    {
        return $this->hasMany(order_details::class);
    }
}

order_details.php

class order_details extends Model
{
    protected $table = 'order_details';

    protected $fillable = ['id','order_id','SKU','unitPrice','quantity','totalPrice'];

    public function order()
    {
        return $this->belongsTo(orders::class);
    }

现在,我想计算每种产品在过去30天,60天和90天的溶胶时间。

要注意的点

  1. products.asin = order_detils.SKU
  2. order_detail表没有订购日期列。
  3. 一个订单可以包含数量大于1的许多产品。

我当前的查询是:-

$products = products::query();

// Some where clauses/filters

$products = $products->get();

foreach($products as $product)
{
    // Getting the order_details which has this product
    $orderIds = order_details::where('SKU','=',$product->asin)->pluck('order_id');

    $product->sales30days = orders::whereIn('id', $orderIds)->whereBetween('date', [Carbon::now()->subDays(30), Carbon::now()])->sum('quantity');
    $product->sales60days = orders::whereIn('id', $orderIds)->whereBetween('date', [Carbon::now()->subDays(60), Carbon::now()])->sum('quantity');
    $product->sales90days = orders::whereIn('id', $orderIds)->whereBetween('date', [Carbon::now()->subDays(90), Carbon::now()])->sum('quantity');
    $product->sales120days = orders::whereIn('id', $orderIds)->whereBetween('date', [Carbon::now()->subDays(120), Carbon::now()])->sum('quantity');
    $product->totalSold = orders::whereIn('id', $orderIds)->sum('quantity');
}

上面的查询为我提供了所需的结果,但是要花费很多时间,并且对性能不友好。我有超过10万种产品。

  1. 我有什么解决方案可以优化此查询?
  2. 可以在此foreach循环之后添加$products->paginate(100)之类的分页吗?

1 个答案:

答案 0 :(得分:2)

问题在于您要进行很多查询,这不可避免地会很慢。该解决方案应该具有更好的性能,因为您只需进行两次查询。

$orders = orders::with(['orderDetails'])->get();
$now = Carbon::now();
$quantities = [];

foreach($orders as $order) {
    $daysOld = $order->date->diffInDays($now);

    foreach ($order->orderDetails as $details) {
        if (!isset($quantities[$details->SKU])) {
            $quantities[$details->SKU]['30'] = 0;
            $quantities[$details->SKU]['60'] = 0;
            $quantities[$details->SKU]['90'] = 0;
            $quantities[$details->SKU]['120'] = 0;
            $quantities[$details->SKU]['total'] = 0;
        }

        if ($daysOld <= 30) {
            $quantities[$details->SKU]['30'] += $details->quantity;
        }

        if ($daysOld <= 60) {
            $quantities[$details->SKU]['60'] += $details->quantity;
        }
        
        if ($daysOld <= 90) {
            $quantities[$details->SKU]['90'] += $details->quantity;
        }

        if ($daysOld <= 120) {
            $quantities[$details->SKU]['120'] += $details->quantity;
        }

        $quantities[$details->SKU]['total'] += $details->quantity;
    }
}

return products::all()->map(function ($product) use ($quantities) {
    $product->sales30days  = $quantities[$product->asin]['30'];
    $product->sales60days  = $quantities[$product->asin]['60'];
    $product->sales90days  = $quantities[$product->asin]['90'];
    $product->sales120days = $quantities[$product->asin]['120'];
    $product->salesTotal   = $quantities[$product->asin]['total'];

    return $product;
});