For software development and maintenance, contact me at contact@appsoftware.com or via appsoftware.com


Database Connection Pooling: How much of an overhead is it?

Tue, 28 Mar 2023 by garethbrown

To try to quantify this (using a PostrgeSQL instance), I ran an integration test under C# / XUnit. The test uses two different configuration files, one with Pooling=false, the other with Pooling=true.

The two connection strings were similar to below, with the only difference being the Pooling value.

Host=localhost;User ID=postgres;Password=xxxx;Database=test_db;Port=35432;Pooling=false;
Host=localhost;User ID=postgres;Password=xxxx;Database=test_db;Port=35432;Pooling=true;

The test is using some custom utility classes, and Dapper (a light weight ORM). The query runs against a table with a small number of rows so as to get as close to testing only the difference in connection resource reuse as possible.

[Theory]
[InlineData("appsettings.DbConnectionTests.NoPooling.secret.json", 1000)]
[InlineData("appsettings.DbConnectionTests.WithPooling.secret.json", 1000)]
public async Task ConnectionSpeedTestWithPooling(string componentAppSettingsFileName, int iterations)
{
    var configurationRoot = new ConfigurationBuilder()
        .AddJsonFile(componentAppSettingsFileName, optional: true, reloadOnChange: true)
        .Build();

    var databaseConnectionInfo = new DatabaseConnectionInfo(configurationRoot);

    var totalStopWatch = new Stopwatch();

    totalStopWatch.Start();

    for (var i = 0; i < iterations; i++)
    {
        using (var unitOfWork = new UnitOfWork(databaseConnectionInfo))
        {
            unitOfWork.ExecuteScalar("SELECT COUNT(*) FROM test_table;");
        }
    }

    totalStopWatch.Stop();

    _testOutputHelper.WriteLine($"Total Elapsed MS: {totalStopWatch.ElapsedMilliseconds}, Total MS: {totalStopWatch.ElapsedMilliseconds}, Average Per Query MS: {totalStopWatch.ElapsedMilliseconds / iterations}");
}

The output for the Pooling=false variant:

Total Elapsed MS: 7513, Total MS: 7513, Average Per Query MS: 7

The output for the Pooling=true variant:

Total Elapsed MS: 1072, Total MS: 1072, Average Per Query MS: 1

So the correct choice for you depends on your priority. Using connection pooling appears to significantly reduce overall load on the server by a factor of 7. On a per connection basis however, we are only looking at a difference of 6ms. In my current use case, we're trying to avoid connection starvation on an AWS RDS postgres instance that backs many containerized instances of an application, so we may opt to switch off / limit connection pooling.

Information regarding connection string parameters for PostgreSQL can be found here.

https://www.npgsql.org/doc/connection-string-parameters.html


The information provided on this Website is for general informational and educational purposes only. While we strive to provide accurate and up-to-date information, we make no warranties or representations, express or implied, as to the accuracy, completeness, reliability, or suitability of the content, including code samples and product recommendations, presented on this Website.

The use of any information, code samples, or product recommendations on this Website is entirely at your own risk, and we shall not be held liable for any loss or damage, direct or indirect, arising from or in connection with the use of this Website or the information provided herein.
UI block loader
One moment please ...