【问题标题】:.net SqlCommandTimeOut and the connection pool.net SqlCommandTimeOut 和连接池
【发布时间】:2012-03-20 06:22:05
【问题描述】:

假设我们正在执行许多不同的 sql 命令,而 SqlCommand.CommandTimeout 的默认值是 30 秒。

让我们假设其中一些 sql 命令只是长查询,我们可能会遇到超时异常。

如果我错了,请纠正我,这个异常只是因为 .Net 不想再等待了,但是如果我们使用连接池,这个连接可能保持打开状态,所以那个 sql 语句可能仍然在SQL服务器端?或者无论我们是否使用连接池,这些系统之间都有一些隐藏的通信突然停止?

只是想知道机制是什么,它会影响 SQL 服务器的性能。我的意思是,如果查询真的很长,例如需要 10 分钟才能运行,如果它仍在运行,它可能只会减慢服务器的速度,因为没有人可以得到结果。

更新

所以我在这里专门询问连接池,肯定是代码将通过异常处理关闭连接,或者我们可以假设正在使用由@dash 命名的首选模式的代码。问题是如果我在那个 SqlConnection 对象上调用 Close() 或 Dispose() 方法,它会返回到连接池,而不是物理上关闭它。

我问它何时返回到池中,那个长查询是否仍在 SQL Server 端运行。如果可能的话,如何避免这种情况。

再次更新

感谢@dash 提到数据库事务,是的,回滚会使其等待,我们还没有关闭连接并将其返回到池中。那么,如果它只是一个长的选择查询或更新,而只是一个单独的更新而不涉及任何数据库事务呢?具体来说,我想知道有没有一种方法可以告诉 SQL Server 我现在不需要结果,请停止运行它?

【问题讨论】:

  • 否;没有办法——你可以杀死 SQL Server 上正在运行的进程,但你真的只需要让 SQL Server 管理它正在做的事情。与所有事情一样,如果您选择运行会降低服务器性能的查询,那么这就是您的选择:-)
  • 您可以使用 SQL KILL 命令杀死 SQL Server 上正在运行的进程。杀死 SPID 并获取 SPID,您可以使用 SELECT @@SPID 或从 sys 表之一获取所有当前进程。

标签: asp.net .net sql-server


【解决方案1】:

这完全取决于您如何真正执行查询;

想象以下查询:

SqlConnection myConnection = new SqlConnection("connection_string");

SqlCommand myCommand = new SqlCommand();
myCommand.Connection = myConnection;
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.CommandTimeout = some_long_time;
myCommand.CommandText = "database_killing_procedure_lol";

myConnection.Open() //Connection's now open

myCommand.ExecuteNonQuery();

会发生两件事;一种是这种方法将排队,直到 command.ExecuteNonQuery() 完成。第二个是我们还将在方法执行期间从连接池中绑定一个连接。

如果我们超时会发生什么?好吧,抛出了一个异常 - 一个 Number 属性 = -2 的 SqlException。但是,请记住,在上面的代码中,没有异常管理,所以所发生的只是对象将超出范围,我们需要等待它们被释放。特别是,在这种情况发生之前,我们的连接是不可重用的。

这是首选以下模式的原因之一:

using(SqlConnection myConnection = new SqlConnection("connection_string"))
{
    using(SqlCommand myCommand = new SqlCommand())
    {

        SqlCommand myCommand = new SqlCommand();
        myCommand.Connection = myConnection;
        myCommand.CommandType = CommandType.StoredProcedure;
        myCommand.CommandTimeout = some_long_time;
        myCommand.CommandText = "database_killing_procedure_lol";

        myConnection.Open() //Connection's now open

        myCommand.ExecuteNonQuery();    

    }

}

这意味着,一旦查询完成,无论是自然的(它运行到完成)还是通过异常(超时或其他),资源都会立即返还

在您的具体问题中,有大量查询需要很长时间才能执行,原因有很多。在 Web 应用程序中,您可能有许多用户争夺有限数量的资源;内存,数据库连接,cpu时间等等。因此,将任何这些与昂贵的操作捆绑在一起会降低您的 Web 应用程序的响应能力和性能,或者限制您可以同时服务的用户数量。此外,如果数据库操作成本很高,您也可以占用您的数据库,从而进一步限制性能。

仅出于这个原因,尝试降低数据库查询的执行时间总是值得的。如果你不能,那么你将不得不小心你可以同时运行多少这些类型的查询。

编辑:

所以您实际上对 SQL Server 端发生的事情很感兴趣...答案是...这取决于! CommandTimeout 实际上是一个客户端事件-您的意思是,如果查询时间超过 n 秒,那么我不想再等待了。 SQL Server 被告知是这种情况,但它仍然需要处理当前正在执行的操作,因此实际上可能需要一些时间才能 SQL Server 完成查询。它会尝试对此进行优先排序,但仅此而已。

对于交易尤其如此;如果您正在运行包含在事务中的查询,并且您将其作为异常管理的一部分回滚,那么您必须等到回滚完成。

看到人们恐慌并开始针对运行查询的 SQL 进程 ID 发出 KILL 命令也很常见。如果命令正在运行事务,这通常是一个错误,但对于长时间运行的选择来说通常是可以的。

SQL Server 必须管理其状态以保持一致。客户端不再侦听的事实意味着您浪费了工作,但 SQL Server 仍然需要自行清理。

所以是的,ASP.Net 方面的事情会很好,因为它不在乎,但是 SQL Server 仍然必须完成它开始的工作,或者达到可以安全放弃该工作的程度,或者回滚已打开的任何交易的任何更改。

这显然会对数据库服务器的性能产生影响,具体取决于查询!

即使是事务之外的长时间运行的 SELECT 或 UPDATE 或 INSERT 也必须完成。 SQL Server 会尽快尝试并放弃它,但前提是这样做是安全的。显然,特别是对于 UPDATES 和 INSERT,它必须达到数据库仍然一致的程度。对于 SELECT,它会尝试尽快结束。

【讨论】:

  • 对不起,我不清楚我的问题,我问的是连接池,但没有更好地练习 'using' 关键字,请查看我更新的问题。
  • 是一样的。如果您在完成连接后没有立即释放它们,那么它们将无法在连接池中重复使用,直到它们被释放。该示例强调了您如何无意中保持连接的时间比您预期的要长。最后一部分讨论了执行许多长时间运行的查询时可能遇到的性能问题。
  • 嘿,我刚刚更新了我的问题,请检查一下,我真的在问一个不同的问题,即我确实关闭了连接并返回到连接池,它是否仍然在 sql server 端运行。我不是在问.Net 如何处理连接池。谢谢
  • 答案通常是肯定的——它仍然会继续运行。我在最后添加了一个讨论这个的部分。
  • 谢谢你,虽然找不到正式的文件我还是想接受你的回答
【解决方案2】:

感谢@dash 提到数据库事务,是的 回滚将使其等待,我们不会关闭连接并且 把它放回游泳池呢。那么,如果它只是一个长选择查询或 更新,但只有一个单独的更新,没有任何数据库 涉及交易?特别是我想知道有没有办法 我们可以告诉 SQL Server 我现在不需要结果 停止运行它?

我认为此链接将满足需求 Link1 Link2

【讨论】:

  • 请注意文档 - “尝试取消 SqlCommand 的执行” - 操作词是“尝试” - 恐怕不能保证。
【解决方案3】:

SqlConnection.ClearPool() 方法可能正在等待您寻找。以下帖子涉及到这一点。

How to force a SqlConnection to physically close, while using connection pooling?

【讨论】:

    猜你喜欢
    • 2019-01-03
    • 1970-01-01
    • 2020-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 2010-09-05
    相关资源
    最近更新 更多