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

时间:2018-09-08 17:33:56

标签: php sql laravel-5

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

控制器:

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

使此视图/报告更“可扩展”的最佳方法是什么?

我一直在考虑创建一个命令,该命令可以在一夜之间计算出每个客户的总销售额,并将结果放入“客户”表中,但这意味着白天的数字并不准确...

3 个答案:

答案 0 :(得分:2)

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

  

我一直在考虑创建计算总数的命令   过夜每位客户的销售额,并将结果放入客户表

这是一个不错的选择。

  

但这意味着白天的数字不正确...

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

这应该可以实现总销售额。

答案 1 :(得分:1)

  1. 确保您在customer_id列上有一个索引。
  2. 搜索方法以使用laravel在2列上执行“ SQL SUM”。
  3. 尝试找到某种方法用SUM对2执行“ SQL GROUP BY。这样做将替换#2
    • 加快应用程序速度的一种好方法是避免循环调用数据库。这就是#3的建议(本例中的循环是您的View中的@foreach,而数据库调用是InvoiceLine::...->get();中的totalSales()

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

我对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插件编写代码。

答案 2 :(得分:0)

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

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