假设我们正在执行许多不同的sql命令,而SqlCommand.CommandTimeout
则默认值为30秒。
让我们假设其中一些sql命令只是长查询,我们可能会得到超时异常。
如果我错了,请纠正我,这个例外只是因为.Net不想再等了,但如果我们使用连接池,这个连接可能会保持打开状态,那么sql语句可能仍会在SQL服务器端?或者这些系统之间存在一些隐藏的通信,无论我们是否使用连接池,都会突然停止它?
只想知道机制是什么,它会影响SQL Server的性能。我的意思是如果查询真的很长,如果它仍在运行需要10分钟才能运行它可能只会减慢服务器的速度,因为没有人能够得到结果。
更新
所以这里我特别询问连接池,它肯定是代码将通过异常处理关闭连接,或者我们可以假设使用的代码是@dash在这里命名的首选模式。问题是如果我在该SqlConnection对象上调用Close()或Dispose()方法,它将返回到连接池,它不会在物理上关闭它。
我问它何时返回池中,那个长查询是否仍在SQL Server端运行。如果可能的话,如何避免这种情况。
再次更新
感谢@dash提到有关数据库事务的信息,是的,回滚将使它等待,我们没有关闭连接并将其返回到池中。那么,如果只是一个长期的选择查询或更新但只是一个单独的更新而不涉及任何数据库事务呢?特别是我想知道有没有一种方法可以告诉SQL Server我现在不需要结果请停止运行它?
答案 0 :(得分:5)
这完全取决于你如何执行查询;
想象一下以下查询:
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,它会尽快结束。
答案 1 :(得分:0)
感谢@dash提及数据库事务,是的 回滚将使它等待,我们没有关闭连接和 把它还给游泳池吧。那么如果它只是一个长期的选择查询或者 更新但只有一个没有任何数据库的单独更新 涉及交易?特别是我想知道有没有办法 我们现在可以告诉SQL Server我不需要结果 停止运行它?
答案 2 :(得分:0)
SqlConnection.ClearPool()方法可能正在等待您正在寻找。以下帖子涉及到这一点。
How to force a SqlConnection to physically close, while using connection pooling?