Repository navigation
perf: match page stats views compute only the match being viewed - #639
Merged
Merged
Conversation
v_match_player_buy_types, v_match_lineup_buy_types and v_match_lineup_map_stats partitioned and grouped by match_map_id only, so the page's match_id filter could not pass below the window, DISTINCT ON or GROUP BY: every read computed the views for every match on the panel. match_id is now a key of each, which match_map_id already implies, so the rows are unchanged.
…ed, and the guard compares like with like Review found v_match_player_opening_duels and v_player_match_map_roles had the same blockers (plus CTEs used twice, which Postgres materializes past any filter) and v_match_lineup_map_stats still scanned match_maps in fk_lineups. match_id is now a key of each, those CTEs are NOT MATERIALIZED, and fk_lineups joins on match_id. The growth guard measured its baseline on stale statistics and so compared two plans; it now ANALYZEs and compares 75 against 150 other matches, covering all five views. New hand-derived tests for opening duels (with a trade) and roles.
Review found NOT MATERIALIZED on first_kills made reads that no match filter narrows (the profile by steam_id, role-filtered leaderboards) scan every kill twice: 131,958 -> 209,429 buffers. opening now reads first_kills once through a LATERAL VALUES pair, so the CTE needs no forcing; those reads are back to base and match reads stay pushed down. A plan test pins one scan of player_kills per use.
lukepolo
force-pushed
the
perf/match-stats-views-pushdown
branch
from
October 16, 2026 16:04
c6f50a1 to
4cabd7a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The match page's buy-type, map-stats, opening-duel and roles views computed their result for every match on the panel and only then kept the one being viewed. On 5stack.gg that made them 105–266ms per read, and the cost grows with the whole database.
A filter can only pass below a window function,
DISTINCT ONorGROUP BYon one of its keys. It also can't reach into a CTE used twice unless that CTE isNOT MATERIALIZED.match_idis now a key of each of those across the five views, and the kill and first-kill joins match onmatch_id. Opening duels' twice-used CTEs (round_sides,fk) areNOT MATERIALIZED. The roles view instead builds openings from one pass overfirst_kills, because forcing it inline doubled the reads no match filter narrows (the profile, role-filtered leaderboards).match_map_idalready impliesmatch_id, so the output is unchanged;player_kills.match_idisNOT NULLwith a foreign key to matches.Same rows: each view's full output on a 600-match bench hashes identically before and after.
Measured through Hasura's own SQL, with 100,800 kills on the panel:
v_match_player_buy_typesv_match_lineup_buy_typesv_match_lineup_map_statsv_match_player_opening_duelsv_player_match_map_rolestest/match-stats-views.spec.tspins, on hand-built matches:These pass on main too, and
views.spec.tsruns unchanged. A plan test pins one scan ofplayer_killsper use for roles read by player.A guard reads one match at 75 and at 150 other matches, with fresh statistics both times. On main the five views grow +324 / +78 / +2,019 / +9,273 / +5,617 buffers; on this PR they grow at most +16.