Skip to content

Commit 9b420fc

Browse files
committed
Improve performance of getting score board
Adding some early filters to avoid lifting more activities than necessary to calculate the scores.
1 parent 7352191 commit 9b420fc

File tree

1 file changed

+21
-38
lines changed

1 file changed

+21
-38
lines changed

Tevling/Services/ChallengeService.cs

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Globalization;
12
using System.Reactive.Subjects;
23
using Microsoft.EntityFrameworkCore;
34

@@ -308,48 +309,31 @@ public async Task<ScoreBoard> GetScoreBoardAsync(int challengeId, CancellationTo
308309
{
309310
await using DataContext dataContext = await dataContextFactory.CreateDbContextAsync(ct);
310311

311-
var result = await dataContext.Challenges
312-
.Select(
313-
c => new
314-
{
315-
Challenge = c,
316-
Athletes = c.Athletes!
317-
.Select(
318-
a => new
319-
{
320-
Athlete = a.Name,
321-
/*
322-
This is not possible with the SQLite provider as it has no support for the APPLY
323-
operation which EFCore requires.
324-
Leaving the idea in here in case a different DB provider is used in the future.
325-
326-
Score = a.Activities!
327-
.Where(a => c.ActivityTypes.Length == 0 || c.ActivityTypes.Contains(a.Details.Type))
328-
.Select(a => a.Details.DistanceInMeters).Sum()
329-
*/
330-
a.Activities,
331-
}),
332-
})
333-
.AsSplitQuery()
334-
.FirstAsync(x => x.Challenge.Id == challengeId, ct);
312+
Challenge challenge = await GetChallengeByIdAsync(challengeId, ct)
313+
?? throw new Exception($"Challenge ID {challengeId} not found");
314+
315+
int[] athleteIds = [.. challenge.Athletes!.Select(a => a.Id)];
335316

336-
AthleteScore[] scores = result.Athletes
317+
Activity[] activities = await dataContext.Activities
318+
.Where(activity =>
319+
activity.Details.StartDate >= challenge.Start &&
320+
activity.Details.StartDate < challenge.End &&
321+
(challenge.ActivityTypes.Count == 0 || challenge.ActivityTypes.Contains(activity.Details.Type)) &&
322+
athleteIds.Contains(activity.AthleteId))
323+
.ToArrayAsync(ct);
324+
325+
AthleteScore[] scores = [.. challenge.Athletes!
337326
.Select(
338-
a => new
327+
athlete => new
339328
{
340-
a.Athlete,
341-
Activities = a.Activities!
342-
.Where(
343-
a => a.Details.StartDate >= result.Challenge.Start &&
344-
a.Details.StartDate < result.Challenge.End &&
345-
(result.Challenge.ActivityTypes.Count == 0 ||
346-
result.Challenge.ActivityTypes.Contains(a.Details.Type))),
329+
Athlete = athlete.Name,
330+
Activities = activities.Where(activity => activity.AthleteId == athlete.Id),
347331
})
348332
.Select(
349333
a => new
350334
{
351335
a.Athlete,
352-
Sum = result.Challenge.Measurement switch
336+
Sum = challenge.Measurement switch
353337
{
354338
ChallengeMeasurement.Distance => a.Activities.Select(x => x.Details.DistanceInMeters).Sum(),
355339
ChallengeMeasurement.Time => a.Activities.Select(x => x.Details.MovingTimeInSeconds).Sum(),
@@ -361,17 +345,16 @@ operation which EFCore requires.
361345
.Select(
362346
s =>
363347
{
364-
string score = result.Challenge.Measurement switch
348+
string score = challenge.Measurement switch
365349
{
366350
ChallengeMeasurement.Distance => $"{s.Sum / 1000:0.##} km",
367351
ChallengeMeasurement.Time => TimeSpan.FromSeconds(s.Sum).ToString("g"),
368352
ChallengeMeasurement.Elevation => $"{s.Sum:0.##} m",
369-
_ => s.Sum.ToString(),
353+
_ => s.Sum.ToString(CultureInfo.InvariantCulture),
370354
};
371355

372356
return new AthleteScore(s.Athlete, score);
373-
})
374-
.ToArray();
357+
})];
375358

376359
return new ScoreBoard(scores);
377360
}

0 commit comments

Comments
 (0)