如何在ASP.net应用程序中检测SqlServer连接泄漏?

34

我目前正在对一个ASP.net 2.0应用程序进行GUI测试。 RDBMS是SQL Server 2005。主机是Win Server 2003 / IIS 6.0。

由于该应用程序是由不释放源代码的外部公司编写的,因此我没有该应用程序的源代码。

我注意到当我重启IIS时,该应用程序表现良好,但在经过几个小时的打开和关闭浏览器后,应用程序会变得越来越慢。我想知道这种行为是否是由于程序员的错误关闭连接操作引起的:我怀疑数据库中存在打开的连接泄漏。

我猜.NET垃圾收集器最终会将它们关闭,但是...那可能要花一段时间,对吗?

我有SQL Server Management Studio,并且我确实从活动监视器中注意到有相当多的连接打开在数据库中。

根据上面所说的所有内容,以下是与主要问题相关的一些问题:

  1. 在SQL Server 2005中是否有任何方法可以知道是否存在连接池中等待使用的连接还是被应用程序使用的已打开连接?

  2. 是否有好的在线/纸质资源可以向我展示如何使用性能计数器或其他工具来帮助跟踪这些问题?

  3. 如果性能计数器是最佳解决方案,那么我应该监视哪些变量?


连接池是否已启用? - Gulzar Nazim
是的。当我遇到类似的问题时,我发现它在应用程序中被设置为false。 - Gulzar Nazim
通常情况下,它由开发人员关闭,并在部署后在web.config/connectionstrings中被遗忘,这是一个常见的部署错误。 - Bogdan Maxim
2
记录一下,1)开发人员不应该关闭连接池(为什么要无缘无故地使开发环境变得不够真实?),2)泄漏问题在使用连接池和不使用连接池时同样容易发生,因此关于连接池的整个观点都是完全无关紧要的。 - Kirk Woll
6个回答

65

在研究类似问题时,我发现了这个帖子。以下是一种在SQL Server中调试泄漏连接的好方法:

SELECT S.spid, login_time, last_batch, status, hostname, program_name, cmd,
(
      select text from sys.dm_exec_sql_text(S.sql_handle)
) as last_sql
FROM sys.sysprocesses S
where dbid > 0
and DB_NAME(dbid) = '<my_database_name>'
and loginame = '<my_application_login>'
order by last_batch asc

这将为您提供特定数据库和登录的所有开放连接,以及在该连接上执行的最后一个sql语句,按执行该sql语句的时间排序。
由于连接池,您不能仅仅依靠有很多连接挂起来告诉您是否存在连接泄漏,因为即使从代码中正确关闭它们,连接池也会保留连接。但是,如果确实存在连接泄漏,您将看到一些连接变成“冻结状态”——它们将出现在上述查询中,“last_batch”时间戳将永远不会更改。其他连接也会挂起,但每次在它们上运行新的sql时,“last_batch”时间戳都会更新。因此,效果是冻结的连接将浮动到此查询的顶部。
如果您拥有相关应用程序的源代码,则此功能为调试提供了非常有价值的最后执行的孤立连接的sql语句。
注意:'loginame'(缺少'n')的拼写错误在sys.sysprocesses视图中。上述陈述是正确的。

https://learn.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-sysprocesses-transact-sql?view=sql-server-ver15


1
这个查询非常有帮助。我只用了几分钟就能找出我们存在的一个严重连接泄漏问题。谢谢! - Matthew Rodatus

7

我曾经遇到过这个问题,发现SQL Server Profiler是一个非常好的工具。我在短时间内对网站进行了测试,并注意到有许多连接被创建(使用sp_who),但这些连接并没有被Connection Pool重用。因此,我打开了SQL Server Profiler,并检查代码中所有对存储过程的调用是否都带有“sp_reset_connection”调用。如果在新批处理开始之前没有这个调用,你就缺少第一个连接。


2
在分析器中留意缺失的“sp_reset_connection”是一个很好的提示,谢谢! - Constantin

2
您可以随时从web.config中检查连接字符串(主要是如果它们启用了连接池并且启用了任何连接限制)。
此外,如果您正在使用IIS 6,则可以将Web应用程序设置为使用单独的应用程序池,并设置其他选项以回收内存和进程。
关于性能计数器,您可以检查垃圾回收器运行的时间、应用程序使用的内存等信息。
如果您有访问SQL Server的权限,可以监视从应用程序发起的连接(每个已安装的SQL Server实例都定义了性能计数器)。
MSDN Magazine上有一些文章。 您还可以使用SOS调试库附加到应用程序的进程并手动检查它。
如果没有源代码,请尝试使用Reflector获取应用程序的源代码(它们非常有用于调试)。
@稍后编辑:您还可以在stackoverflow.com上检查此问题

2
关于( ADO.NET性能计数器)的MSDN参考非常清楚,可以在分析应用程序时查找什么。您可以使用Windows中内置的perfmon应用程序监视计数器。
除此之外,我建议学习有关ADO.NET连接池的知识。如果您真的怀疑是他们代码中的错误,您可以使用Red Gate's Reflector(目前免费),该软件将MSIL反汇编为C#以供查看。

1

我会先查看连接并查看活动时间,看看是否可以找到保持连接打开的项目。

我认为,如果解决方案是重新启动IIS,您还应该查看应用程序的内存使用情况,以查看是否存在内存泄漏或其他导致其占用空间增长的问题。

如果打开的连接是一个问题,在活动监视器中,您将看到大量没有活动的连接。

对于性能计数器,您可以开始查看“SQL Server:常规统计信息”性能对象。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接