我构建了一个应用程序来跟踪销售情况。在我的客户视图中,我想要一个包含每位客户总销售额的列,但是随着客户群的增长,列表加载的速度越来越慢。这就是我所做的(简体):
控制器:
$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;
}
使此视图/报告更“可扩展”的最佳方法是什么?
我一直在考虑创建一个命令,该命令可以在一夜之间计算出每个客户的总销售额,并将结果放入“客户”表中,但这意味着白天的数字并不准确...
答案 0 :(得分:2)
这似乎是一个非常有趣的问题。
我一直在考虑创建计算总数的命令 过夜每位客户的销售额,并将结果放入客户表
这是一个不错的选择。
但这意味着白天的数字不正确...
您可以通过执行以下操作来保持数字的准确性: 通过在每次开具发票时增加客户表计数。
这应该可以实现总销售额。
答案 1 :(得分:1)
customer_id
列上有一个索引。SUM
”。SUM
对2执行“ SQL GROUP BY
。这样做将替换#2
@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秒!