Проблема в вашем случае, по сути, такова:
Вы выполняете полный расчет каждый раз, когда звоните getTotalPoints
, ... и каждый вызов включает в себя 10 вызовов staticsRepository
(fuckup 1: почему, черт возьми, у вас есть хранилище в сущности? - это запах кода!) и подсчитывает дочерние объекты (+1 запрос для каждой коллекции).
Я действительно очень надеюсь, что ваш staticsRepository
не зависит от пользователя , потому что в этом случае запросы даже не кэшируются. по вашему мнению, они, вероятно, нет.
Итак, по сути, у вас есть проблема n+1
(см. № 5) .
Вы , вероятно, можете написать специализированный запрос , который вычисляет totalScore
s для всех ваших пользователей в базе данных, но, честно говоря, я здесь не для того, чтобы обучать вас DQL или SQL. Тем не менее, сделайте исследование, или вы тратите так много потенциала для улучшения ...
Теперь есть несколько вариантов (неполный список):
делать все это в базе данных , каждый раз, все время. В этом случае вы добавляете функцию к вашему UserRepository
, которая выполняет запрос либо для одного User
, либо возвращает всех пользователей, включая их общие баллы. Создание представления базы данных, включающего этот запрос в качестве поля, может сделать это даже прозрачным для вашего кода. но это также может быть сделано в построителе запросов, то есть DQL, ... или SQL. Может быть, вам понадобятся расширения доктрины.
это решение является чрезвычайно эффективным и всегда дает достаточно недавние результаты
реализует логику в php, сохраняет результат в базе данных (добавляя новое поле БД для totalScore
), пересчитывает в удобный момент времени. Это решение очень эффективно, если все сделано правильно, но может привести к слегка устаревшим результатам. (удобный момент времени - как ... ежедневно в полночь или один раз в час, или каждые 5 минут - если ваш сервер может остановить это, добавьте некоторые средства, чтобы выяснить, изменился ли счет: отметка времени всего, что меняет счет, сохранить метка времени ...)
это решение несколько производительно, обновление (которое, вероятно, будет выполнено с помощью заданий cron), и оно всегда дает правильные и свежие результаты. - недавний == ваш интервал. по сути, это упрощает ваш текущий подход ... в сочетании с 1 для очень хороших результатов.
использовать совокупные поля , что существенно обновляет счет в базе данных - почти как в 2. но - всякий раз, когда он изменяется. Посмотрите на агрегатные поля и выясните, как адаптировать это к вашему варианту использования. Пожалуйста, обратите внимание на условия гонки и как их избежать. В зависимости от вашего конкретного подхода это может снизить производительность для многих действий, но значительно повысит производительность при запросе высоких баллов ...
это ОЧЕНЬ высокоэффективно с высокими показателями и всегда дает достаточно недавние результаты, НО вам приходится иметь дело с условиями гонки и всеми обновлениями очков, которые могут быть чрезвычайно раздражающими и подверженными ошибкам!
Мой выбор был бы 1. Это требует, чтобы вычисление было выражено в sql или dql, что, вероятно, можно сделать.