Rewrite orderedUserMMRBySeason as window function to avoid 12s plan

The max(id) self-join let the query planner pick a nested-loop plan when
it misjudged a season's row count (e.g. a freshly started season whose
stats are dwarfed by older seasons), making the query take ~12s on the
current season. The window-function form references Skill once and is
plan-stable regardless of stats. Output is identical.
This commit is contained in:
Kalle
2026-06-08 17:25:01 +03:00
parent 76654c87bd
commit f21f2f7d76

View File

@@ -1,24 +1,24 @@
import { sql } from "~/db/sql";
import type { Tables } from "~/db/tables";
// Window function (latest Skill row per user) rather than a self-join against a
// `max(id)` subquery: the self-join lets the planner pick a nested-loop plan when
// it misjudges the season's row count (e.g. a freshly started season whose stats
// are dwarfed by older seasons), which made this query take ~12s. This form is
// plan-stable regardless of stats.
const userStm = sql.prepare(/* sql */ `
select
"Skill"."ordinal",
"Skill"."matchesCount",
"Skill"."userId"
from
"Skill"
inner join (
select "userId", max("id") as "maxId"
select "ordinal", "matchesCount", "userId"
from (
select
"ordinal",
"matchesCount",
"userId",
row_number() over (partition by "userId" order by "id" desc) as "rn"
from "Skill"
where "Skill"."season" = @season
group by "userId"
) "Latest" on "Skill"."userId" = "Latest"."userId" and "Skill"."id" = "Latest"."maxId"
where
"Skill"."season" = @season
and "Skill"."userId" is not null
order by
"Skill"."ordinal" desc
where "season" = @season and "userId" is not null
)
where "rn" = 1
order by "ordinal" desc
`);
export function orderedUserMMRBySeason(season: number) {