Laravel Оптимизировать сумму запроса - PullRequest
2 голосов
/ 13 марта 2019

Я хотел бы получить сумму, пополнить счет, снять и считать счет.В настоящее время у меня есть ~ 10,335,633 строк данных (~ 1,8ГБ), для вычисления суммы требуется более 7 секунд.Как мне улучшить мой запрос, чтобы сделать его быстрее?

Запрос:

$depositQuery = Deposit::whereBetween('created_at', [$start, $end])->approved();
$withdrawQuery = Withdraw::whereBetween('created_at', [$start, $end])->approved();

if ($request->has('user_id')) {
    $depositQuery = $depositQuery->where('user_id', $request->user_id);
    $withdrawQuery = $withdrawQuery->where('user_id', $request->user_id);
}

$deposits = $depositQuery->sum('amount');
$withdraws = ($withdrawQuery->sum('amount')) * -1;
$net = $deposits + $withdraws;

Результат:

Deposit     Withdraw     Net Amount
20,946.00   15,066.00    5,880.00

1 Ответ

2 голосов
/ 13 марта 2019

По сути, laravel eloquent не имеет ничего общего с оптимизацией sum(), он просто переводит ваш код в SQL-запрос. И попадаю в ваш вопрос

Помните: вы не можете оптимизировать саму функцию суммы * (если вы не настоящий джедай)

У вас есть 1M записей в вашей базе данных, и сумма MySQL должна пройти через все записи, чтобы вычислить сумму. и в этом случае 7 секунд это нормально, я думаю. Согласно этому вопросу здесь , sum() в таблице записей 7M заняло около 22 секунд. Так что в зависимости от вашей схемы, машины и т. Д. Скорость может немного отличаться здесь и там.

Так как же вы можете улучшить время отклика?

Каким-то образом вам придется уменьшить количество записей, прежде чем передать его на обработку sum().

Один из способов, который, как я полагаю, вы можете сделать, состоит в том, что вы можете вычислить суммы по 10 000 записей / порций записей и сохранить их в отдельной таблице с соответствующим диапазоном даты и времени. Общий термин для этого - архивирование . Затем, когда вам нужно вычислить сумму для заданного диапазона дат, используйте предыдущую полную сумму из новой таблицы и используйте ее. Вы можете настроить хронирование, чтобы обновлять эту таблицу за день или что-то в этом роде, чтобы убедиться, что данные всегда правильные.

Другим способом является разбиение таблиц MySQL . Что также кажется многообещающим способом. Что также является своего рода архивированием. но я не очень опытен в том, чтобы комментировать. Google должен помочь вам в этом.

Индексирование по столбцам, таким как created_at и столбцу, который вы используете для утвержденной области, должно улучшить время отклика, но не так, как если бы вы использовали технику архивирования.

Кроме того, у меня есть MySQLmysql кеш запросов для ответа по той же ссылке, которую я указал выше, больше информации . Который вы можете попробовать использовать. Но с mysql 8 он устарел и, более того, он не будет работать должным образом, если у вас запущено несколько экземпляров и если у вас есть многораздельные таблицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...