为什么C#连接池会出现这么多的sp_resetconnections?

8
我们有一个使用C#编写的Web服务,它对MS SQL Server 2005数据库进行了多次调用。该代码使用Using块结合C#的连接池。

在SQL跟踪期间,我们看到了许多“sp_resetconnection”调用。其中大部分都很短<0.5秒,但有时我们会得到长达9秒的调用。

从我所读到的内容来看,“sp_resetconnection”与连接池有关,基本上重置了打开连接的状态。我的问题:

  • 为什么需要重置打开的连接状态?
  • 为什么会有这么多这样的调用!
  • 什么原因会导致对“sp_resetconnection”的调用需要花费非常长的时间。

这对我来说是个谜,我感激任何和所有的帮助!


如果你有一个分析器跟踪数据,显示sp_reset_connection花费了很长时间,为什么不看一下客户端在调用之前做了哪些工作?这应该会给你一个被拆除的状态的想法。 - ahains
可能是What does sp_reset_connection do?的重复问题。 - Michael Haren
4个回答

13
重置操作可以将连接重置,而无需重新连接。它会清除连接中的SET或USE操作等内容,使每个查询都从一个干净的状态开始。
连接仍然在被重用。以下是一个详尽的列表:(链接)
sp_reset_connection 会重置连接的以下方面:
- 重置所有错误状态和编号(例如 @@error)。 - 停止执行并行查询的父 EC 的所有子线程的 EC。 - 等待任何未完成的 I/O 操作。 - 释放连接在服务器上持有的所有缓冲区。 - 解锁连接使用的任何缓冲区资源。 - 释放连接拥有的所有内存分配。 - 清除连接创建的任何工作表或临时表。 - 终止连接拥有的所有全局游标。 - 关闭所有已打开的 SQL-XML 句柄。 - 删除任何已打开的与 SQL-XML 相关的工作表。 - 关闭所有系统表。 - 关闭所有用户表。 - 删除所有临时对象。 - 中止打开的事务。 - 在注册分布式事务时从其中退出。 - 在当前数据库中减少用户引用计数;这将释放共享数据库锁。 - 释放获取的锁。 - 释放可能已经获取的所有句柄。 - 将所有 SET 选项重置为默认值。 - 重置 @@rowcount 值。 - 重置 @@identity 值。 - 使用 dbcc traceon() 重置任何会话级跟踪选项。
但是,sp_reset_connection 不会重置以下内容:
- 安全上下文,这就是为什么连接池根据精确的连接字符串匹配连接的原因。
  • 如果您使用 sp_setapprole 进入应用程序角色,由于应用程序角色无法还原,因此请注意
  • 事务隔离级别(!)

  • 1
    这是sp_reset_connection是做什么的?的解释,其中一部分说:“数据访问API层(如ODBC、OLE-DB和SqlClient)在从连接池中重新使用连接时调用(内部)存储过程sp_reset_connection。它这样做是为了在重新使用之前重置连接的状态。”然后它给出了该系统存储过程所做的一些具体内容。这是一件好事。

    1

    每次从池中请求新连接时,都会调用sp_resetconnection。这是因为池无法保证用户(即您,程序员)已将连接留在正确的状态下。例如,返回具有未提交事务的旧连接会很糟糕。

    调用次数应与获取新连接的次数相关。

    至于某些调用需要花费相当长的时间,我不确定。可能是服务器正在忙于处理其他事情,也可能是网络延迟。


    1
    基本上,这些调用是清除状态信息的。如果您有任何打开的DataReaders,那么它将需要更长的时间来完成。这是因为您的DataReaders只保留单个行,但可能会拉取更多行。在重置可以继续之前,它们也必须被清除。因此,请确保您的所有内容都处于using()语句中,并且没有在某些语句中保持打开状态。
    这种情况下您有多少个总连接?
    如果您最多有5个连接并且您已经达到了5个,则调用重置将被阻止,并且似乎需要很长时间。实际上,它没有,只是被阻塞等待池化连接可用。
    另外,如果您正在运行SQL Express,由于线程要求非常容易被阻止(在完整的SQL Server中也可能发生,但不太可能)。
    如果关闭连接池会发生什么?

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