Запросы занимают слишком много времени и пямяти, т.к. в БД очень много данных. Мне нужно как-то ускорить. Уже много раз менял код и пока не знаю как сделать еще быстрее.
У меня есть три графика на главной странице. Там мы выбираем с какой даты по какую показать и я получаю данные под каждый день.
Сначала перевожу дату в нужный формат:
if ($from) {
$dateFrom = Date::createFromFormat('d.m.Y G:i', $from);
}
if ($to) {
$dateTo = Date::createFromFormat('d.m.Y G:i', $to);
}
Создаю массив, в который буду складывать значения:
$tableDate = [
[
'count_sales' => [],
],
[
'new_users' => [],
],
[
'success_payments' => [],
],
'days' => [],
];
Потом получаю кол-во дней между этими датами.
// Все дни с первого по последнего.
$count_days = floor(abs(strtotime($dateFrom) - strtotime($dateTo)) / 86400) + 1;
После этого я делаю запросы через конструктор. Специально группирую их по датам, дабы потом распарсить.
$count_sales = ActiveService::orderBy('created_at')
->whereBetween('updated_at', [$dateFrom, $dateTo])
->get('created_at')
->groupBy(function($events) {
return Carbon::parse($events->created_at)->format('d.m.Y');
});
$new_users = User::orderBy('created_at')
->whereBetween('created_at', [$dateFrom, $dateTo])
->get('created_at')
->groupBy(function($events) {
return Carbon::parse($events->created_at)->format('d.m.Y')
});
$success_payments = HistoryPayment::orderBy('created_at')
->whereBetween('created_at', [$dateFrom, $dateTo])
->where('operation', 'top_up')
->where('status_transaction', 'success')
->where('payment_id', '!=', '0')
->select(['amount', 'created_at'])
->get()
->groupBy(function($events) {
return Carbon::parse($events->created_at)->format('d.m.Y');
});
Вот что я получаю:
(на примере $count_sales)
Теперь делаю следующее (ниже поясню)
for ($i=0; $i < $count_days; $i++) {
$day = date('d.m.Y', strtotime($dateFrom) + 86400 * $i);
array_push($tableDate['days'], $day);
$tableDate[0]['count_sales'][$i] = 0;
$tableDate[1]['new_users'][$i] = 0;
$tableDate[2]['success_payments'][$i] = 0;
// Кол-во успешных активаций (продаж) по дням.
if($count_sales->get($day) !== null) {
$count = $count_sales->get($day)->count();
$tableDate[0]['count_sales'][$i] = $count;
}
// Кол-во регистраций по дням
if($new_users->get($day) !== null) {
$count = $new_users->get($day)->count();
$tableDate[1]['new_users'][$i] = $count;
}
// Сумма успешных оплат по дням
if($success_payments->get($day) !== null) {
$amounts = $success_payments->get($day);
foreach ($amounts as $value) {
$tableDate[2]['success_payments'][$i] += $value->amount;
}
}
}
Я создаю цикл, в которым перебираю каждый день.
Т.е. переменная $day - это определенный день в формате d.m.Y.
Как видите, у меня есть проверки типа:
if($count_sales->get($day) !== null)
Просто БД запросы что показывал выше (скриншот выше) возвращают только дни, в которых есть нужные нам записи. А спокойно может быть такое, что будет какая-то дата, например 22.12.2021 в которую ничего не будет куплено/пополнено и т.д. Поэтому я сначала проверяю дату, которую мы парсим сейчас на то, есть ли у нас данные для нее. Ну и если есть, я их вписываю.
В конце я просто все возвращаю:
return new Collection([
'tableDate' => $tableDate,
]);
Ну так вот, запросы занимают много времени и памяти. Спокойно может выйти ошибка 500 ну или просто грузится 30 секунд - пару минут.
Мне бы хотя-бы совет или указать на то, что я сделал не так и как это можно сделать лучше.