2013-08-05 135 views
1

我们遇到了一个重要的应用程序在生产中的问题。作为一种短期修复,我们增加很多地方的命令超时整个代码:500秒命令超时 - 太长?

var cmd = new SqlCommand(szSQL, conn) {CommandTimeout = _cmdTimeout}; 

开发人员正在使用500秒(8+分钟)的初始默认。在我们得到长期解决之前,这是我们的解决方案。我关心的是使用的秒数。 8分钟以上似乎很长时间(太长),我想知道使用这段时间可能会引入哪些其他问题。尝试并保持在3-4分钟之内会更好吗?或者8就好了?

+5

我不敢问这个东西可能需要3-4分钟... – canon

+3

我想你“等问题”将是员工/客户 – Jonesopolis

+2

嘛一群愤怒的暴徒,我想这取决于。您认为有多少用户愿意等待8分钟以上才能获得结果?我认为你应该专注于优化查询,而不是担心你的超时时间应该多长。 –

回答

2

我认为在必要时使用8分钟作为超时没有问题。 AFAIK,SSMS在运行查询时有无限超时!

不过我建议在此基础上略有不同的方法提取的代码:

private static bool IsRetryAfterException(SqlException aSqlExc) 
{ 
    if (aSqlExc != null) 
    { 
    // If anybody finds a better way than this, please update! 
    return aSqlExc.Message.Contains("The timeout period elapsed prior to completion of the operation or the server is not responding"); 
    } 
    else 
    throw new ArgumentNullException("The parameter 'aSqlExc' cannot be null."); 
} 

private int CallExecuteNonQuery(SqlCommand aCmd) 
{ 
    for (int iRetry = 1; iRetry <= m_MaxTimeoutRetry; iRetry++) 
    try 
    { 
     return aCmd.ExecuteNonQuery(); 
    } 
    catch (SqlException wSqlE) 
    { 
     if (iRetry == m_MaxTimeoutRetry || !IsRetryAfterException(wSqlE)) 
     throw; 

     // otherwise, we double the timeout and retry 
     aCmd.CommandTimeout = 2 * aCmd.CommandTimeout; 
     // let SQL breathe a bit! 
     System.Threading.Thread.Sleep(aCmd.CommandTimeout * 10); 
    } 

    // This code cannot be reached but the compiler thinks otherwise 
    // this is because it cannot know that m_MaxTimeoutRetry is always >= 1 for the for-loop 
    throw new DataAccessException(); 
} 

在我们的代码,所有查询都通过CallExecuteNonQuery方法调用。 这可能很难为您更改您的代码,但您可以使用Lambda表达式,并轻松地修改您现有的代码,以便它通过这种独特的方法,几乎​​没有变化...

所以问题是为什么使用一个循环和重试?这是因为SQL死锁。我的经验是,最好让命令超时并快速回复30秒,如果超时并让SQL呼吸,而不是让所有查询默认超时,那么最好再试一次。

我希望这有助于并有意义。

+0

提示+1。实际上我们有一个名为SqlDeadlockHelper的类(在不同的部门),它重试。这将是我们重构工作的一部分。 –