Skip to content

Commit 650175e

Browse files
authored
Test better batching performance by avoiding individual UPDATE statements (#381)
* Test better batching performance by avoiding individual `UPDATE` statements * Fix empty inserts failing * Fix equality
1 parent 605a2ed commit 650175e

1 file changed

Lines changed: 32 additions & 13 deletions

File tree

osu.Server.Queues.ScoreStatisticsProcessor/Commands/Maintenance/RecalculateModMultipliersCommand.cs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public class RecalculateModMultipliersCommand
2929
[Option(CommandOptionType.SingleValue, Template = "--batch-size")]
3030
public int BatchSize { get; set; } = 5000;
3131

32+
[Option(CommandOptionType.SingleValue, Template = "--flush-size")]
33+
public int FlushSize { get; set; } = 1000;
34+
3235
[Option(CommandOptionType.SingleOrNoValue, Template = "--dry-run")]
3336
public bool DryRun { get; set; }
3437

@@ -41,12 +44,12 @@ public class RecalculateModMultipliersCommand
4144
[Option(CommandOptionType.SingleOrNoValue, Template = "--run-indexing")]
4245
public bool RunIndexing { get; set; }
4346

44-
private readonly StringBuilder sqlBuffer = new StringBuilder();
45-
4647
private ElasticQueuePusher? elasticQueuePusher;
4748

4849
private readonly List<ElasticQueuePusher.ElasticScoreItem> elasticItems = new List<ElasticQueuePusher.ElasticScoreItem>();
4950

51+
private readonly List<(ulong id, long newTotalScore)> pendingUpdates = new List<(ulong id, long newTotalScore)>();
52+
5053
[UsedImplicitly]
5154
public async Task<int> OnExecuteAsync(CancellationToken cancellationToken)
5255
{
@@ -94,6 +97,8 @@ public async Task<int> OnExecuteAsync(CancellationToken cancellationToken)
9497

9598
foreach (var score in scoresWithMods)
9699
{
100+
cancellationToken.ThrowIfCancellationRequested();
101+
97102
string source = score.is_legacy_score ? "stable" : "lazer ";
98103

99104
var beatmap = await BeatmapStore.GetBeatmapAsync(score.beatmap_id, conn);
@@ -156,10 +161,12 @@ public async Task<int> OnExecuteAsync(CancellationToken cancellationToken)
156161
if (Verbose)
157162
Console.WriteLine($"[{score.id,11} {source}] Updating score: {oldTotalScore,8} (old) -> {newTotalScore,8} (new)");
158163

159-
sqlBuffer.Append($@"UPDATE `scores` SET `total_score` = {newTotalScore} WHERE `id` = {score.id};");
164+
pendingUpdates.Add((score.id, newTotalScore));
160165
if (RunIndexing)
161166
elasticItems.Add(new ElasticQueuePusher.ElasticScoreItem { ScoreId = (long?)score.id });
162167
updated++;
168+
169+
flush(conn);
163170
}
164171

165172
lastId += (ulong)BatchSize;
@@ -174,20 +181,31 @@ public async Task<int> OnExecuteAsync(CancellationToken cancellationToken)
174181
return 0;
175182
}
176183

184+
private readonly StringBuilder statementBuilder = new StringBuilder();
185+
177186
private void flush(MySqlConnection conn, bool force = false)
178187
{
179-
int bufferLength = sqlBuffer.Length;
180-
181-
if (bufferLength == 0)
182-
return;
183-
184-
if (bufferLength > 1024 || force)
188+
if (pendingUpdates.Count >= FlushSize || force)
185189
{
186190
if (!DryRun)
187191
{
188-
Console.WriteLine();
189-
Console.WriteLine($"Flushing sql batch ({bufferLength:N0} bytes)");
190-
conn.Execute(sqlBuffer.ToString());
192+
if (pendingUpdates.Count > 0)
193+
{
194+
Console.WriteLine();
195+
Console.WriteLine($"Flushing sql updates ({pendingUpdates.Count:N0} rows)");
196+
197+
statementBuilder.Clear();
198+
statementBuilder.AppendLine("UPDATE `scores` SET `total_score` = CASE `id`");
199+
200+
foreach (var row in pendingUpdates)
201+
statementBuilder.AppendLine($"WHEN {row.id} THEN {row.newTotalScore}");
202+
203+
statementBuilder.AppendLine("END WHERE `id` IN (");
204+
statementBuilder.AppendLine(string.Join(',', pendingUpdates.Select(u => u.id)));
205+
statementBuilder.AppendLine(")");
206+
207+
conn.Execute(statementBuilder.ToString());
208+
}
191209

192210
if (RunIndexing && elasticItems.Count > 0)
193211
{
@@ -197,7 +215,8 @@ private void flush(MySqlConnection conn, bool force = false)
197215
}
198216

199217
elasticItems.Clear();
200-
sqlBuffer.Clear();
218+
statementBuilder.Clear();
219+
pendingUpdates.Clear();
201220
}
202221
}
203222
}

0 commit comments

Comments
 (0)