fix: batch standings updates to eliminate N+1 queries in recalculate (#75)
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m54s
All checks were successful
Build Docker Image / build (pull_request) Successful in 2m54s
Replace per-game update_standings() calls with pre-fetched dicts and in-memory accumulation, then a single bulk_update at the end. Reduces ~1,100+ queries for a full season to ~5 queries. Closes #75 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
da679b6d1a
commit
d3b9355f26
130
app/db_engine.py
130
app/db_engine.py
@ -1317,13 +1317,137 @@ class Standings(BaseModel):
|
|||||||
with db.atomic():
|
with db.atomic():
|
||||||
Standings.bulk_create(create_teams)
|
Standings.bulk_create(create_teams)
|
||||||
|
|
||||||
# Iterate through each individual result
|
# Pre-fetch all data needed for in-memory processing (avoids N+1 queries)
|
||||||
|
standings_by_team_id = {
|
||||||
|
s.team_id: s
|
||||||
|
for s in Standings.select().where(Standings.team << s_teams)
|
||||||
|
}
|
||||||
|
teams_by_id = {t.id: t for t in Team.select().where(Team.season == season)}
|
||||||
|
divisions_by_id = {
|
||||||
|
d.id: d
|
||||||
|
for d in Division.select().where(Division.season == season)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Iterate through each individual result, tallying wins/losses in memory
|
||||||
# for game in Result.select_season(season).where(Result.week <= 22):
|
# for game in Result.select_season(season).where(Result.week <= 22):
|
||||||
for game in StratGame.select().where(
|
for game in StratGame.select().where(
|
||||||
(StratGame.season == season) & (StratGame.week <= 18) & (StratGame.game_num.is_null(False))
|
(StratGame.season == season) & (StratGame.week <= 18) & (StratGame.game_num.is_null(False))
|
||||||
).order_by(StratGame.week, StratGame.game_num):
|
).order_by(StratGame.week, StratGame.game_num):
|
||||||
# tally win and loss for each standings object
|
away_stan = standings_by_team_id.get(game.away_team_id)
|
||||||
game.update_standings()
|
home_stan = standings_by_team_id.get(game.home_team_id)
|
||||||
|
away_team_obj = teams_by_id.get(game.away_team_id)
|
||||||
|
home_team_obj = teams_by_id.get(game.home_team_id)
|
||||||
|
if None in (away_stan, home_stan, away_team_obj, home_team_obj):
|
||||||
|
continue
|
||||||
|
away_div = divisions_by_id.get(away_team_obj.division_id)
|
||||||
|
home_div = divisions_by_id.get(home_team_obj.division_id)
|
||||||
|
if away_div is None or home_div is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Home Team Won
|
||||||
|
if game.home_score > game.away_score:
|
||||||
|
home_stan.wins += 1
|
||||||
|
home_stan.home_wins += 1
|
||||||
|
away_stan.losses += 1
|
||||||
|
away_stan.away_losses += 1
|
||||||
|
|
||||||
|
if home_stan.streak_wl == 'w':
|
||||||
|
home_stan.streak_num += 1
|
||||||
|
else:
|
||||||
|
home_stan.streak_wl = 'w'
|
||||||
|
home_stan.streak_num = 1
|
||||||
|
|
||||||
|
if away_stan.streak_wl == 'l':
|
||||||
|
away_stan.streak_num += 1
|
||||||
|
else:
|
||||||
|
away_stan.streak_wl = 'l'
|
||||||
|
away_stan.streak_num = 1
|
||||||
|
|
||||||
|
if game.home_score == game.away_score + 1:
|
||||||
|
home_stan.one_run_wins += 1
|
||||||
|
away_stan.one_run_losses += 1
|
||||||
|
|
||||||
|
if away_div.division_abbrev == 'TC':
|
||||||
|
home_stan.div1_wins += 1
|
||||||
|
elif away_div.division_abbrev == 'ETSOS':
|
||||||
|
home_stan.div2_wins += 1
|
||||||
|
elif away_div.division_abbrev == 'APL':
|
||||||
|
home_stan.div3_wins += 1
|
||||||
|
elif away_div.division_abbrev == 'BBC':
|
||||||
|
home_stan.div4_wins += 1
|
||||||
|
|
||||||
|
if home_div.division_abbrev == 'TC':
|
||||||
|
away_stan.div1_losses += 1
|
||||||
|
elif home_div.division_abbrev == 'ETSOS':
|
||||||
|
away_stan.div2_losses += 1
|
||||||
|
elif home_div.division_abbrev == 'APL':
|
||||||
|
away_stan.div3_losses += 1
|
||||||
|
elif home_div.division_abbrev == 'BBC':
|
||||||
|
away_stan.div4_losses += 1
|
||||||
|
|
||||||
|
home_stan.run_diff += game.home_score - game.away_score
|
||||||
|
away_stan.run_diff -= game.home_score - game.away_score
|
||||||
|
# Away Team Won
|
||||||
|
else:
|
||||||
|
home_stan.losses += 1
|
||||||
|
home_stan.home_losses += 1
|
||||||
|
away_stan.wins += 1
|
||||||
|
away_stan.away_wins += 1
|
||||||
|
|
||||||
|
if home_stan.streak_wl == 'l':
|
||||||
|
home_stan.streak_num += 1
|
||||||
|
else:
|
||||||
|
home_stan.streak_wl = 'l'
|
||||||
|
home_stan.streak_num = 1
|
||||||
|
|
||||||
|
if away_stan.streak_wl == 'w':
|
||||||
|
away_stan.streak_num += 1
|
||||||
|
else:
|
||||||
|
away_stan.streak_wl = 'w'
|
||||||
|
away_stan.streak_num = 1
|
||||||
|
|
||||||
|
if game.away_score == game.home_score + 1:
|
||||||
|
home_stan.one_run_losses += 1
|
||||||
|
away_stan.one_run_wins += 1
|
||||||
|
|
||||||
|
if away_div.division_abbrev == 'TC':
|
||||||
|
home_stan.div1_losses += 1
|
||||||
|
elif away_div.division_abbrev == 'ETSOS':
|
||||||
|
home_stan.div2_losses += 1
|
||||||
|
elif away_div.division_abbrev == 'APL':
|
||||||
|
home_stan.div3_losses += 1
|
||||||
|
elif away_div.division_abbrev == 'BBC':
|
||||||
|
home_stan.div4_losses += 1
|
||||||
|
|
||||||
|
if home_div.division_abbrev == 'TC':
|
||||||
|
away_stan.div1_wins += 1
|
||||||
|
elif home_div.division_abbrev == 'ETSOS':
|
||||||
|
away_stan.div2_wins += 1
|
||||||
|
elif home_div.division_abbrev == 'APL':
|
||||||
|
away_stan.div3_wins += 1
|
||||||
|
elif home_div.division_abbrev == 'BBC':
|
||||||
|
away_stan.div4_wins += 1
|
||||||
|
|
||||||
|
home_stan.run_diff -= game.away_score - game.home_score
|
||||||
|
away_stan.run_diff += game.away_score - game.home_score
|
||||||
|
|
||||||
|
# Bulk save all modified standings
|
||||||
|
with db.atomic():
|
||||||
|
Standings.bulk_update(
|
||||||
|
list(standings_by_team_id.values()),
|
||||||
|
fields=[
|
||||||
|
Standings.wins, Standings.losses,
|
||||||
|
Standings.home_wins, Standings.home_losses,
|
||||||
|
Standings.away_wins, Standings.away_losses,
|
||||||
|
Standings.one_run_wins, Standings.one_run_losses,
|
||||||
|
Standings.streak_wl, Standings.streak_num,
|
||||||
|
Standings.run_diff,
|
||||||
|
Standings.div1_wins, Standings.div1_losses,
|
||||||
|
Standings.div2_wins, Standings.div2_losses,
|
||||||
|
Standings.div3_wins, Standings.div3_losses,
|
||||||
|
Standings.div4_wins, Standings.div4_losses,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# Set pythag record and iterate through last 8 games for last8 record
|
# Set pythag record and iterate through last 8 games for last8 record
|
||||||
for team in all_teams:
|
for team in all_teams:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user