From 1e88b7b460f4ed3a761ef3d235e82f63997dbe99 Mon Sep 17 00:00:00 2001 From: Ramon Smits Date: Tue, 12 Sep 2023 16:43:45 +0200 Subject: [PATCH] Optimize TSQL outbox cleanup by reducing batch size and adding rowlock hint (#1249) --- .../OutboxCommandTests.Cleanup.MsSql.approved.txt | 2 +- src/SqlPersistence/Outbox/OutboxPersister.cs | 2 +- src/SqlPersistence/Outbox/SqlDialect_MsSqlServer.cs | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SqlPersistence.Tests/ApprovalFiles/OutboxCommandTests.Cleanup.MsSql.approved.txt b/src/SqlPersistence.Tests/ApprovalFiles/OutboxCommandTests.Cleanup.MsSql.approved.txt index c44e2fa0e..fb8f9ac97 100644 --- a/src/SqlPersistence.Tests/ApprovalFiles/OutboxCommandTests.Cleanup.MsSql.approved.txt +++ b/src/SqlPersistence.Tests/ApprovalFiles/OutboxCommandTests.Cleanup.MsSql.approved.txt @@ -1,4 +1,4 @@  -delete top (@BatchSize) from [TheSchema].[TheTablePrefixOutboxData] +delete top (@BatchSize) from [TheSchema].[TheTablePrefixOutboxData] with (rowlock) where Dispatched = 'true' and DispatchedAt < @DispatchedBefore \ No newline at end of file diff --git a/src/SqlPersistence/Outbox/OutboxPersister.cs b/src/SqlPersistence/Outbox/OutboxPersister.cs index a880f46dd..424e8f945 100644 --- a/src/SqlPersistence/Outbox/OutboxPersister.cs +++ b/src/SqlPersistence/Outbox/OutboxPersister.cs @@ -20,7 +20,7 @@ class OutboxPersister : IOutboxStorage public OutboxPersister(IConnectionManager connectionManager, SqlDialect sqlDialect, OutboxCommands outboxCommands, Func outboxTransactionFactory, - int cleanupBatchSize = 10000) + int cleanupBatchSize = 4000) // Keep below 4000 to prevent lock escalation { this.connectionManager = connectionManager; this.sqlDialect = sqlDialect; diff --git a/src/SqlPersistence/Outbox/SqlDialect_MsSqlServer.cs b/src/SqlPersistence/Outbox/SqlDialect_MsSqlServer.cs index fe95f8eec..21723ed56 100644 --- a/src/SqlPersistence/Outbox/SqlDialect_MsSqlServer.cs +++ b/src/SqlPersistence/Outbox/SqlDialect_MsSqlServer.cs @@ -75,8 +75,9 @@ internal override string GetOutboxPessimisticCompleteCommand(string tableName) internal override string GetOutboxCleanupCommand(string tableName) { + // Rowlock hint to prevent lock escalation which can result in INSERT's and competing cleanup to dead-lock return $@" -delete top (@BatchSize) from {tableName} +delete top (@BatchSize) from {tableName} with (rowlock) where Dispatched = 'true' and DispatchedAt < @DispatchedBefore"; }