Ensure Proper SQL Server Connection Pooling

by Jun 11, 2012

Coming to SQL Server from both a database developer and DBA background, I maintain that while tuning SQL Server’s ability to handle your application workloads is a viable way to increase performance, another way to bolster performance is to consider architectural and coding practices within your applications.

This is especially true of connection pooling – which Microsoft describes as follows:

Connecting to a database server typically consists of several time-consuming steps. A physical channel such as a socket or a named pipe must be established, the initial handshake with the server must occur, the connection string information must be parsed, the connection must be authenticated by the server, checks must be run for enlisting in the current transaction, and so on.

In practice, most applications use only one or a few different configurations for connections. This means that during application execution, many identical connections will be repeatedly opened and closed. To minimize the cost of opening connections, ADO.NET uses an optimization technique called connection pooling.

The problem, however, with connection pooling is that it can be complex to correctly configure and define – making it non-trivial to implement correctly in some environments.

Connection Pooling Defined

Happily, however, Microsoft has provided some great guidance around how to properly understand and configure Connection Pooling – including the following resources:

An Overview of Connection Pooling in ADO.NET (link)
Cited above, this resource provides a decent overview of what connection pooling is, why it’s important, and how to leverage it properly. It also bypasses a lot of the FUD and bad advice around connection pooling that has sadly crept up over the years – no doubt due to the non-trivial nature of some of the configuration semantics required to get pooling to work correctly under more complex scenarios.

Connection String Details that Define Pooling Considerations (link)
Focusing primarily on how to construct connection strings for use within ADO.NET applications, this resource also helps define the specific components used in connection strings that can be used to regulate and define pool sizes and parameters (near the bottom of the page).

Development and Coding Considerations to avoid ‘leaking’ Connections (link)
While this guidance is decidedly older than the other two sources cited, the section on pooling resources defines best practices for explicitly calling Dispose or Close on expensive resources – including SQL Server database connections. (Most of the problems that I encounter with improper connection pooling are typically due to ‘leaks’ caused by thrown exceptions or improper handling of the need to close connections in order to return them to the pool. That, or developers opening connections prematurely and keeping them open WELL after data has already been collected.)
This resource also covers advice on how to avoid caching or blocking pooled resources – and is a must-read for developers who aren’t using some sort of framework or proven code that manages connection pooling for them.

Detecting Potential Problems with Connection Pooling
Given how hard it can be to get connection pooling working perfectly in more complex environments (or in cases where developers may not have understood the basics or necessity of connection pooling), I always try to check for proper or improper connection pooling when performing SQL Server audits for my consulting clients.

The problem, however, is that the easiest way to rule out or validate problems with connection pooling requires long-term profiling or access to the application servers connecting to SQL Server. As such, I typically run a query similar to the following in order to ‘gut check’ whether or not there might be problems with connection pooling:
SELECT des.program_name,

des.login_name,

des.host_name,

–der.database_id,

COUNT(des.session_id) [Connections]

FROM sys.dm_exec_sessions des

INNER JOIN sys.dm_exec_connections DEC

ON des.session_id = DEC.session_id

WHERE des.is_user_process = 1

–AND des.status != ‘running’

GROUP BY des.program_name,

des.login_name,

des.host_name

–,der.database_id

HAVING COUNT(des.session_id) > 2

ORDER BY COUNT(des.session_id) DESC

This simple query – which isn’t fool-proof – simply interrogates SQL Server’s Dynamic Management Views (DMVs) for information about existing connections and sessions (you can achieve similar results by querying master..sysprocesses in SQL Server 2000 databases). Then, by grouping against common traits shared between existing sessions it’s possible to derive results identifying the logins that have more than two open, existing, connections (or sessions).

Again, this approach isn’t foolproof. For starters, it’s only providing results for the exact point in time when the query is being run. So, there may be problems with connection pooling during different parts of the day – which you’re not going to see with this query unless you run it when there are problems. Likewise, results showing more than 2 connections (or sessions) from the same login may not actually be indicative of improper connection pooling. (For example, this is why the script above also allows for the option to throw the database ID into the mix – as some applications might actually have multiple connections in to different databases – and could still be properly pooled.)

Consequently, if I think I’ve found potential problems, I typically run queries similar to the following – just to get a better feel for what might be causing more than 2 connections per login:
SELECT *

FROM sys.dm_exec_sessions des

WHERE des.login_name = ‘LoginWithMultipleSessionIds’

And, since DMVs sadly don’t do as good of a job of reporting on idle sessions as the older data in master..sysprocesses (the dm_exec_* DMVs are focused on active requests – which makes perfect sense in most cases – but fall short when looking for improperly pooled connections that are just sitting idle), I will also occasionally run a query similar to the following:
SELECT *

FROM MASTER..sysprocesses

WHERE loginame = ‘LoginWithMultipleSessionIds’

Or, I’ll take a look at what each of these sessions was last doing by peeking in on them with DBCC INPUTBUFFER() by passing in the session_id’s of all of their currently defined sessions.

Verifying Connection Pooling

If my initial detection and queries give me any reason to believe that connection pooling might not be configured optimally by calling applications, I can then do some additional research and exploration. And while there are some great approaches out there for using SQL Server Profiler to keep tabs on connections in order to verify connection pooling, I typically prefer to go to the source – and query the Performance Counters on the application servers themselves as there are actually performance counters available which track pooled and non-pooled connections for .NET applications.

Of course, if you’re dealing with non .NET applications, then James Rowland-Jones’s approach listed above is a great way to do further spelunking and validation. Otherwise, if you’re confident that all connections to your database are coming from .NET application or web servers, you can interrogate the .NET CLR Data performance Counter within Windows to track <All instances> of various SQLClient connection pooling details in order to determine if you have non-pooled connections in play – as per Figure 1.

Figure 1: Using Performance Counters to verify proper Connection Pooling.

Similarly, you can also use various .NET Data Provider for SqlServer counters (such as <All instances> of NumberOfNonPooledConnections) to track the number of Pooled and nonPooled connections as well.

Likewise, rather than merely watching these counters from within Performance Monitor, you can easily set up Data Collector Sets to sample these values and track them over time – to make sure that problems with connection pooling aren’t happening at times other than when you happen to be profiling or performing analysis.