5

Before posting this question, I have read several answers on this site: like this and this. Everyone seem to agree that "c# application pools are optimized for multiple calls to the same database."

However, I still observe a substantial performance penalty if I get a connection from the pool. Here are my benchmarks:

    private const string localConnString = "Data Source=(local);Integrated Security=SSPI;database=MyTest;Pooling=true";


    [Test]
    public void GetNewConnectionEveryTime()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < 1000; i++)
        {
            using (var conn = new SqlConnection(localConnString))
            {
                conn.Open();
                const string saveTrancount = "EXEC dbo.TestTran";
                ExecuteSql(conn, saveTrancount);
            }
        }
        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        //Time elapsed: 00:00:00.5576016
    }

    [Test]
    public void ReuseOneConnection()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        using (var conn = new SqlConnection(localConnString))
        {
            conn.Open();
            for (var i = 0; i < 1000; i++)
            {
                const string saveTrancount = "EXEC dbo.TestTran";
                ExecuteSql(conn, saveTrancount);
            }
        }
        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        //Time elapsed: 00:00:00.1110324
    }

    private void ExecuteSql(SqlConnection conn, string sql, int timeout = 0)
    {
        var command = conn.CreateCommand();
        command.CommandText = sql;
        command.CommandType = CommandType.Text;
        command.CommandTimeout = timeout;
        command.ExecuteNonQuery();
    }

Apparently getting a connection from the pool takes four times more time (00:00:00.5576016 - 00:00:00.1110324 appr 0.44) than doing actual work (00:00:00.1110324 in second benchmark). What am I missing?

Edit: I am running these benchmarks against a database created on RAM Disk, so all my database operations are very fast.

Community
  • 1
  • 1
A-K
  • 16,804
  • 8
  • 54
  • 74

2 Answers2

4

You benchmarks make sense to me. It would be even worse if you opened and closed the connection for each iteration without connection pooling, but that's a whole different story. However, when you close a pooled connection, you're instead returning it to the pool: under the covers, the SNAC issues sp_reset_connection and puts the connection back into the pool. Usually, it's a very fast operation (unless blocking kicks in), but it has to take some small but non-zero time.
Re-using the same connection without closing and opening for each iteration, avoids this small lag.
However, if you compared the same use of pooled and non-pooled connections it would have made more sense to me. Have you tried that?

Here's an interesting post on sp_reset_connection

spaghettidba
  • 529
  • 7
  • 17
  • +1 Your answer and link are useful. Regarding your question, I certainly could " compared the same use of pooled and non-pooled connections", but why is it interesting? I usually use connection pooling. Are there any scenarios when I should turn it off? – A-K Jan 09 '13 at 17:57
  • > Are there any scenarios when I should turn it off? Maybe. With failover clustering and database mirroring you _may_ end up with invalid connections in your pool after a fail-over. Instead of turning pooling off completely, you could reset the pool. Don't know if it answers your question. – spaghettidba Jan 09 '13 at 18:21
  • There is a .net platform reliability update that causes a check to see if the connection is still good before reusing it. if the conn isn't good, it'll be re-opened transparently. It's a must for sql azure. – StrayCatDBA Jan 10 '13 at 00:49
  • @StrayCatDBA there are multiple .net platform reliability updates. Which one have you used? – A-K Jan 10 '13 at 22:58
1

+1 to @spaghettidba - I agree, and to add some comments.....

My approach in the past has been to use the same connection multiple times - save having to even go to the connection pool to get a connection each time which I've always assumed (not measured) has some cost as @spaghettidba said.

The main performance benefit of the pool, is the scenario where it doesn't make sense/can't reuse the same connection instance - in which case getting a previously used connection from the pool is much faster as it doesn't actually need to go off and actually try to connect to the server, it just assumes it's there and available - i.e. connection.Open() in my experience doesn't error for a pooled connection even if the server is down - it will just error when you try to execute anything against the connection.

AdaTheDev
  • 142,592
  • 28
  • 206
  • 200
  • +1 yes, connection.Open() does not invoke any activity I can observe in the Profiler. I will only see sp_reset_connection when I run a command against my reused connection. – A-K Jan 09 '13 at 18:54