![](/img/trans.png)
[英]How to force a SqlConnection to physically close, while using connection pooling?
[英]How can I measure login time on a SqlConnection while using pooling?
我想捕获有关使用SqlConnection的应用程序的一些统计信息,特别是其实际登录服务器所花费的时间。
简单的方法如下:
using (SqlConnection connection = ...)
{
Stopwatch loginTimer = Stopwatch.StartNew();
connection.Open()
loginTimer.Stop();
}
所不同的是,我也使用连接池,并且不想将其关闭。 结果,我的指标出现了偏差,因为大多数对.Open()
调用实际上只是从池中获取一个现有的,开放的物理连接,所以我将看到:
00:00:01.39
00:00:00.02
00:00:00.02
00:00:00.02
...
该应用程序使用了足够的连接,并以SqlAzure为目标,因此我希望看到物理登录经常发生。
我尝试过测试连接,然后再尝试:
if (sqlConnection.State != ConnectionState.Open)
{
// Time and call .Open()
}
不幸的是,逻辑SqlConnection不能反映物理连接的状态,因此始终执行if
块。
我知道可以创建我自己的连接池,从中汲取并执行该连接池,但是永远不会关闭,因此我可以通过逻辑连接的状态来跟踪物理连接的实际状态,但是我会真的更喜欢不这样做。
可能您可以使用ClientConnectionId属性来跟踪sql连接。 每次创建新的物理连接时都会重新生成,并在从池中返回连接时保留。 但仅从.net 4.5开始可用。
另一种可能性是仅对某些连接跳过连接池,只是为了测量物理时间,而为其他连接保留池。
例如,您可以具有静态计数器,该计数器将保持递增。 对于每个可被10整除的值,可以将Pooling ='false'添加到连接字符串中,以跳过将其添加到pool中的操作。 这将打开新的连接,您可以测量物理时间。
用一些具体的代码扩展亚历山大的答案。
在对所有连接使用池的限制内,可以通过跟踪SqlClient
为每次物理登录生成的SqlConnection.ClientConnectionId
值,来衡量物理登录到服务器/数据库所花费的时间。 以下是用于测量和报告此时间的示例扩展方法。 要使用它,请将SqlConnection.Open()
调用更改为SqlConnection.Login(out openTime)
,如果发生登录,结果将为true,否则为false。
internal static class SqlConnectionExtension
{
private static readonly PropertyInfo _clientConnectionIdPropertyInfo = typeof(SqlConnection).GetProperty("ClientConnectionId");
private static readonly HashSet<Guid> _clientConnectionIds = new HashSet<Guid>();
/// <summary>
/// Method that calls <see cref="SqlConnection.Open()"/>, measuring the time it takes.
/// </summary>
/// <param name="sqlConnection">The <see cref="SqlConnection"/> to open.</param>
/// <param name="openTime">The total time that the call to <see cref="SqlConnection.Open()"/> took.</param>
/// <returns>True if a login took place; false if a connection was returned from a connection pool.</returns>
public static bool Login(this SqlConnection sqlConnection, out TimeSpan openTime)
{
Stopwatch loginTimer = Stopwatch.StartNew();
sqlConnection.Open();
loginTimer.Stop();
openTime = loginTimer.Elapsed;
#if NET_4_0_3
Guid clientConnectionId = sqlConnection.ClientConnectionId;
#else
Guid clientConnectionId = Guid.Empty;
if (_clientConnectionIdPropertyInfo != null)
{
clientConnectionId = (Guid)_clientConnectionIdPropertyInfo.GetValue(sqlConnection, null);
}
#endif
if (clientConnectionId != Guid.Empty && !_clientConnectionIds.Contains(clientConnectionId))
{
lock (_clientConnectionIds)
{
if (_clientConnectionIds.Add(clientConnectionId))
{
return true;
}
}
}
return false;
}
}
在我自己的环境中,我们仍在使用VS2010,并且并非所有客户端都具有4.0.3多目标包,因此#if NET_4_0_3
部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.