Статистика: один проход по строкам игрока вместо четырёх

Главная гоняла тяжёлый SCORED_CTE пять раз: лидерборд, три запроса профиля (итог,
разбивка по фракциям, форма последних партий) и ещё раз итог для активной группы.
Четыре последних выбирали одни и те же строки одного игрока и отличались только
агрегацией, а стоимость CTE растёт с числом партий во всём приложении, а не в
группе игрока.

Теперь строки игрока тянутся одним запросом, а итог, разбивка и форма считаются из
них в Python. Фильтр по группе — фильтрация того же набора, поэтому блок активной
группы не стоит отдельного прохода. На главной осталось два прохода вместо пяти,
у профиля — один вместо трёх.

Формула сглаженного рейтинга получила Python-версию рядом с SQL-версией, на тех же
константах: в SQL она нужна лидерборду, где агрегация идёт по всем игрокам. Чтобы
две реализации не разъехались (как однажды вышло с кэш-бастером аватара), добавлен
тест, сверяющий цифры профиля с цифрами того же игрока в лидерборде.

Второй тест считает запросы с SCORED_CTE на главной: без него оптимизация тихо
отъедет назад при следующей правке витрин.

#32

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BoiJK9ux8peeyjLb8TYjFf
This commit is contained in:
2026-09-09 20:38:29 +03:00
co-authored by Claude Opus 5
parent 634a4c0e08
commit e0f1ed5fee
3 changed files with 173 additions and 75 deletions
+11
View File
@@ -38,6 +38,17 @@ MATCH_POINTS_SQL = (
)
def smoothed_score(points_sum: float, games: int) -> float | None:
"""Тот же сглаженный рейтинг, что и SMOOTHED_SCORE_SQL, но в Python.
Нужен там, где строки уже вытащены и агрегировать в SQL нечего (профиль игрока).
Держим рядом с SQL-версией и на одних константах: разъехавшиеся реализации одной
формулы — источник расхождений, который потом ловится только глазами."""
if games <= 0:
return None # рейтинга без игр нет — как SUM(...) = NULL в SQL
return (PRIOR_GAMES * PRIOR_MEAN + points_sum) / (PRIOR_GAMES + games) * 100
def leaderboard_sort_key(row: dict) -> tuple:
"""Ключ сортировки топа: счёт ↓, winrate ↓, игры ↓, среднее место ↑, ник ↑."""
return (