【问题标题】:Optimizing Laravel query优化 Laravel 查询
【发布时间】:2020-07-04 06:52:57
【问题描述】:

我正在处理一个需要以 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) 这样的分页吗?

【问题讨论】:

  • 我评论了其中一个答案。你的起点可以更好。您从获得所有产品开始。而是从date <= 120 days 的订单开始。您不需要所有这些产品。您将获得date <= 120 days 订单中的“唯一”产品。它将在数据层过滤版本。然后你可以在应用层迭代它们。

标签: php laravel


【解决方案1】:

问题是您要进行很多查询,而且它不可避免地会很慢。这个解决方案应该有更好的性能,因为您只进行了两次查询。

$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;
}); 

【讨论】:

    猜你喜欢
    • 2018-05-27
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 2017-01-08
    • 2017-10-07
    • 1970-01-01
    相关资源
    最近更新 更多