Я создал приложение для отслеживания продаж. На мой взгляд, мне нужен столбец с общими продажами на одного покупателя, но по мере роста клиентской базы список загружается все медленнее и медленнее. Вот что я сделал (упрощенно):
Контроллер:
$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;
}
Как лучше всего сделать это представление / отчет более «масштабируемым»?
Я думал о создании команды, которая вычисляет общий объем продаж на одного клиента за ночь и помещает результат в таблицу клиентов, но это означает, что числа не будут точными в течение дня ...
это кажется очень интересной проблемой.
I have been thinking in creating command that calculates the total sales per customer overnight and put the result in the customer table
это хороший вариант.
but that means that the numbers won't be accurate during the day...
Вы можете сохранить точные цифры, выполнив следующие действия: путем увеличения счетчика в таблице клиентов каждый раз, когда выставляется счет.
Это должно работать для общих продаж.
customer_id
.SUM
на 2 столбца с помощью laravel".SUM
на 2 с помощью 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
Вы видите, как сразу извлекаются все данные, которые вы пытаетесь распечатать? Я предполагаю, что вы захотите попробовать написать это с помощью Eloquent в Laravel.
Основываясь на ответах выше, я пришел к следующему решению:
Я создал событие: App\Events\InvoiceSaved
, которое отправляется каждый раз, когда счет-фактура "затрагивается" (создается, обновляется или удаляется). Событие App\Events\InvoiceSaved
рассчитает общий объем продаж для клиента и добавит результат в таблицу клиентов (дополнительное поле total_sales). Теперь я могу просто запросить таблицу клиентов, и мне нужно запросить отношение. Время загрузки упало с 7 секунд до 0,5 секунды!