如何使销售报告更具“可扩展性”?

问题描述 投票:1回答:3

我构建了一个应用程序来跟踪销售情况。在我的客户视图中,我想要一个每个客户的总销售额的列,但随着客户群的增长,列表的加载速度越来越慢。这就是我所做的(简化):

控制器:

$customers = App\Customer::get();

视图:

@foreach ($customers as $customer)
{{ $customer->name }} {{ $customer->totalSales() }}
@endforeach

模型:

public function totalSales()
{
     $invoiceLines = InvoiceLine::whereHas('invoice', function ($query) {
        $query->where('customer_id', $this->id);
     })->get();

     $sales = $invoiceLines->reduce(function ($carry, $invoiceLine) {
        return $carry + ($invoiceLine->quantity * $invoiceLine->pricePerUnit);
     });

     return $sales ?: 0;
}

什么是使这种观点/报告更具“可扩展性”的最佳方法?

我一直在考虑创建命令来计算每个客户的总销售额,并将结果放在客户表中,但这意味着这些数字在白天不准确...

php sql laravel-5
3个回答
2
投票

这似乎是一个非常有趣的问题。

我一直在考虑创建命令,计算每个客户的总销售额,并将结果放在客户表中

这是一个不错的选择。

但这意味着这些数字在白天不准确......

您可以通过执行以下操作来保持数字的准确性:通过在每次发票时递增客户表计数。

这应该适用于总销售额。


1
投票
  1. 确保customer_id列上有索引。
  2. 搜索使用laravel“在2列上执行SQL SUM”的方法。
  3. 尝试并找到一些方法来做“用SUM 2上的SQL GROUP BY。这样做将取代#2 加速应用程序的一个好方法是避免在循环中调用数据库。这就是#3的建议(在这种情况下,循环是你视图中的@foreach,数据库调用是InvoiceLine::...->get();中的totalSales()

添加索引(如果缺少)并减少对DB的调用次数将产生最佳结果。

我对Laravel的了解有限,但使用原始SQL的一种方法是:

SELECT c.name, ts.totalSales
FROM customer c
INNER JOIN (
  SELECT customer_id, SUM(quantity * pricePerUnit) as totalSales
  FROM invoice
  GROUP BY customer_id
) ts ON c.id = ts.customer_id

您可以看到您尝试打印的所有数据是如何同时提取的?我假设你想尝试使用Laravel的Eloquent thingy来编写它。


0
投票

基于上面的答案,我得出以下解决方案:

我创建了一个事件:App\Events\InvoiceSaved,每次发票被“触摸”(创建,更新或删除)时都会被调度。 App\Events\InvoiceSaved事件将计算客户的总销售额并将结果添加到customers表(额外字段total_sales)。现在我可以查询我的customers表并需要查询关系。加载时间从7秒降至0.5秒!

© www.soinside.com 2019 - 2024. All rights reserved.