Skip to content

Instantly share code, notes, and snippets.

@cheenamalhotra
Last active November 16, 2022 02:33
Show Gist options
  • Save cheenamalhotra/1441826f98b0158df5d08969df0788eb to your computer and use it in GitHub Desktop.
Save cheenamalhotra/1441826f98b0158df5d08969df0788eb to your computer and use it in GitHub Desktop.
Test SqlConnection.OpenAsync performance
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
namespace SqlClientTests
{
public class TestOpenAsyncPerformance
{
private const int Parallelism = 50;
private const int ConnCount = 300;
private const string ConnString = "Server=<azuresqldb>.database.windows.net; Authentication=Active Directory Interactive; Initial Catalog=master; Max Pool Size=500;";
public static async Task Main(string[] args)
{
await WarmUpSqlClientAsync(count: 10).ConfigureAwait(false);
Stopwatch stopwatch = Stopwatch.StartNew();
await ConnectAsync(new Configuration() { Connections = ConnCount, Parallels = Parallelism, Pooling = true, Mars = false }).ConfigureAwait(false);
await Console.Out.WriteLineAsync($"\nTotal time taken: \t{stopwatch.ElapsedMilliseconds / 1000} seconds.").ConfigureAwait(false);
}
private static async Task ConnectAsync(Configuration c)
{
SqlConnection.ClearAllPools();
await Task.Delay(100).ConfigureAwait(false);
SqlConnection[] connCache = new SqlConnection[c.Connections];
long[] msPerConn = new long[c.Connections];
Parallel.For(0, ConnCount, i => connCache[i] = new SqlConnection(new SqlConnectionStringBuilder(ConnString)
{
Pooling = c.Pooling,
MultipleActiveResultSets = c.Mars
}.ConnectionString));
Stopwatch stopwatch = Stopwatch.StartNew();
int i = 0;
await Console.Out.WriteAsync($"\nConfig: \t{c}").ConfigureAwait(false);
Stopwatch stopwatchOuter = Stopwatch.StartNew();
await Parallel.ForEachAsync(connCache, new ParallelOptions() { MaxDegreeOfParallelism = c.Parallels }, async (conn, cancellationToken) =>
{
stopwatch.Restart();
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
msPerConn[i] = stopwatch.ElapsedMilliseconds;
Interlocked.Increment(ref i);
}).ConfigureAwait(false);
await SummarizeAsync(msPerConn).ConfigureAwait(false);
await Console.Out.WriteLineAsync($"\t= {stopwatchOuter.ElapsedMilliseconds / 1000} seconds total time.").ConfigureAwait(false);
}
private static async Task SummarizeAsync(long[] timeArray)
{
long total = 0;
Array.ForEach(timeArray, t => total += t);
await Console.Out.WriteAsync($"\t= {total / ConnCount} ms / connection").ConfigureAwait(false);
}
private static async Task WarmUpSqlClientAsync(int count = 0)
{
for (int i = 0; i < count; i++)
{
await using var con = new SqlConnection(ConnString);
await con.OpenAsync().ConfigureAwait(false);
}
}
private class Configuration
{
public int Connections { get; set; }
public int Parallels { get; set; }
public bool Mars { get; set; }
public bool Pooling { get; set; }
public override string ToString()
{
return $"{nameof(Connections)}: {Connections} \t" +
$"{nameof(Parallels)}: {Parallels} \t" +
$"{nameof(Mars)}: {Mars} \t" +
$"{nameof(Pooling)}: {Pooling}";
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.0.1" />
<!--<ProjectReference Include="..\src\Microsoft.Data.SqlClient\netcore\src\Microsoft.Data.SqlClient.csproj" />-->
</ItemGroup>
</Project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment