超时已过期.操作完成之前经过的超时时间或服务器没有响应.该语句已终止

Sil*_*ght 280 c# asp.net timeout sqlcommand sql-server-2008-r2

我的网站上有很多用户(每天20000-60000),这是一个移动文件的下载站点.我可以远程访问我的服务器(Windows Server 2008-R2).
我之前收到"服务器不可用"错误,但现在看到连接超时错误.
我不熟悉这个 - 它为什么会发生,我该如何解决?

完整错误如下:

'/'应用程序中的服务器错误.超时已过期.操作完成之前经过的超时时间或服务器没有响应.该语句已终止.描述:执行当前Web请求期间发生未处理的异常.请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息.

异常详细信息:System.Data.SqlClient.SqlException:超时已过期.操作完成之前经过的超时时间或服务器没有响应.该语句已终止.

来源错误:

在执行当前Web请求期间生成了未处理的异常.可以使用下面的异常堆栈跟踪来识别有关异常的起源和位置的信息.

堆栈跟踪:

[SqlException(0x80131904):超时已过期.操作完成之前经过的超时时间或服务器没有响应.语句已终止.]
System.Data.SqlClient.SqlConnection.OnError(SqlException异常,Boolean breakConnection
)+404
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()+ 412 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior ,SqlCommand cmdHandler,SqlDataReader dataStream,BulkCopySimpleResultSet bulkCopyHandler,TdsParserStateObject stateObj)+1363
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,RunBehavior runBehavior,String resetOptionsString)+6387741
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,Boolean async)+6389442
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String method,DbAsyncResult result)+538
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName,Boolean sendToPipe)+689
System.Data.SqlClient.SqlCommand.Execu teNonQuery()+ 327
NovinMedia.Data.DbObject.RunProcedure(String storedProcName,IDataParameter []参数,Int32和rowsAffected)+209
DataLayer.OnlineUsers.Update_SessionEnd_And_Online(Object Session_End,Boolean Online)+440
NiceFileExplorer.Global.Application_Start(Object sender,EventArgs e)+163

[HttpException(0x80004005):超时已过期.操作完成之前经过的超时时间或服务器没有响应.该语句已被终止.]
System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context,HttpApplication app)+405205​​3
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext,HttpContext context,MethodInfo [] handlers)+191
System.Web.HttpApplication. InitSpecial(HttpApplicationState状态,MethodInfo的[]处理程序,IntPtr的appContext,HttpContext的上下文)352
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr的appContext,HttpContext的上下文)407
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr的appContext)375

[HttpException(0x80004005):超时已过期.操作完成之前经过的超时时间或服务器没有响应.该语句已被终止.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context)+11686928 System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context)+141 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr,HttpContext context)+4863749


编辑后编辑:
Application_StartGlobal.asax内容如下:

protected void Application_Start(object sender, EventArgs e)
{
    Application["OnlineUsers"] = 0;

    OnlineUsers.Update_SessionEnd_And_Online(
        DateTime.Now,
        false);

    AddTask("DoStuff", 10);
}
Run Code Online (Sandbox Code Playgroud)

被调用的存储过程是:

ALTER Procedure [dbo].[sp_OnlineUsers_Update_SessionEnd_And_Online]
    @Session_End datetime,
    @Online bit
As
Begin
    Update OnlineUsers
    SET
        [Session_End] = @Session_End,
        [Online] = @Online

End
Run Code Online (Sandbox Code Playgroud)

我有两种获取在线用户的方法:

  1. 运用 Application["OnlineUsers"] = 0;
  2. 另一个使用数据库

因此,对于方法#2,我重置了所有的OnlineUsers Application_Start.该表中有超过482,751条记录.

Mar*_*len 325

看起来你的查询花费的时间比它应该的要长.从堆栈跟踪和代码中,您应该能够确切地确定查询是什么.

这种类型的超时可能有三个原因;

  1. 某处有一个僵局
  2. 数据库的统计信息和/或查询计划缓存不正确
  3. 查询过于复杂,需要进行调整

死锁可能很难解决,但很容易确定是否是这种情况.使用Sql Server Management Studio连接到数据库.在左窗格中,右键单击服务器节点,然后选择" 活动监视器".看看正在运行的进程.通常大多数将闲置或运行.出现问题时,您可以通过进程状态识别任何阻止的进程.如果右键单击该流程并选择详细信息,它将显示该流程执行的最后一个查询.

第二个问题将导致数据库使用次优查询计划.可以通过清除统计信息来解决:

exec sp_updatestats
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,你也可以尝试

dbcc freeproccache
Run Code Online (Sandbox Code Playgroud)

当您的服务器负载很重时,不应该这样做,因为它会暂时产生很大的性能,因为所有存储过程和查询在首次执行时都会重新编译.但是,由于您有时会说出问题,并且堆栈跟踪指示您的应用程序正在启动,我认为您正在运行仅偶尔运行的查询.通过强制SQL Server不重用以前的查询计划,您可能会更好.有关如何执行此操作的详细信息,请参阅此答案.

我已经触及了第三个问题,但您可以通过手动执行查询(例如使用Sql Server Management Studio)轻松确定查询是否需要调优.如果查询需要很长时间才能完成,即使重置统计信息后,您也可能需要对其进行调整.有关这方面的帮助,您应该在新问题中发布确切的查询.

  • 我遇到了同样的错误,但是在一个'只是'花了8秒的查询中......你对'exec sp_updatestats`的提示解决了我的问题.非常感谢! (37认同)
  • 这肯定不是僵局.它可能是由过度阻塞引起的,但死锁会在一秒钟内解决,并产生不同的错误.这可能是过度阻塞,但不是死锁. (5认同)
  • 解决这样的问题几乎不是调整超时或连接池大小的问题.你需要潜入并找出根本原因.如果您需要帮助解决根本原因,您可以发布自己的问题. (2认同)

Ela*_*tep 144

在运行存储过程的代码中,您应该具有以下内容:

SqlCommand c = new SqlCommand(...)
//...
Run Code Online (Sandbox Code Playgroud)

添加这样一行代码:

c.CommandTimeout = 0;
Run Code Online (Sandbox Code Playgroud)

这将等待操作完成所需的时间.

  • 您还应该知道0值不是[推荐](http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout%28v=VS.100%29.aspx ):*值为0的指示没有限制,应该在CommandTimeout中避免,因为执行命令的尝试将无限期地等待.*最好了解命令花费的时间,并在需要时增加Timeout值. (134认同)
  • 我不会陷入不推荐它的陷阱.它对我和我的日常计划任务非常有用:无限超时不会阻止进程完成并在出现错误时返回错误.简单地说,它只是允许您在需要时允许查询完成,而不会在以后给自己带来问题,因为您没有为该过程分配足够的时间来完成.您还可以通过多线程避免锁定程序. (9认同)
  • 我同意Otiel的观点并且给出了你的答案:当你将commandTimeout设置为0时,你不会让网络服务器有机会从没有响应的数据库服务器中恢复.其次,当您达到默认超时时,您应该考虑查看原因.在大多数情况下,修复查询比提高超时时间更好. (5认同)
  • 有时您只需要等待一个查询一段未知的时间。而且它根本与错误的查询无关。就像想象一下从连接不良的数据库中下载一个巨大的文件一样。要理解的一件非常重要的事情是,将超时设置为零不会阻止您获得所有其他类型的异常。如果查询失败、连接断开或发生其他任何情况,您将收到异常。它唯一做的就是消除时间因素。 (3认同)
  • Yes 对于大数据传输不设置这没有意义。如果您要传输数百万行,那么 Otiel 和 BlackHawkDesign 所说的就没有意义。 (2认同)
  • 在 20 年以数据为中心的开发中,我从来不需要这样做。几乎总是有一个相当简单的解决方案,可以提供更好的性能,并且不会为单个进程整天处理数据库创造机会。绝大多数数据库性能问题都可以调整到执行速度快几个数量级。也就是说,您等待 3 小时才能完成的过程可能会调整为 3 分钟甚至 3 秒。 (2认同)

小智 24

您可以设置CommandTimeoutSQL命令的属性以允许长时间运行的SQL事务.

您可能还需要查看导致超时的SQL查询.


mat*_*eek 12

虽然所有早期的回复都解决了这个问题,但并没有涵盖所有案例.

Microsoft已承认此问题并在2011年针对受支持的操作系统进行了修复,因此如果您获得堆栈跟踪如下:

Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
at System.Data.SqlClient.TdsParserStateObject.ReadSni(DbAsyncResult asyncResult, TdsParserStateObject stateObj)
Run Code Online (Sandbox Code Playgroud)

您可能需要更新.NET程序集.

出现此问题是由于镜像数据库的连接重试算法中的错误.

使用重试算法时,数据提供程序等待第一次读取(SniReadSync)调用完成.该调用将发送到运行SQL Server的后端计算机,并通过将连接超时值乘以0.08来计算等待时间.但是,如果响应很慢并且在等待时间到期之前未完成第一个SniReadSync调用,则数据提供程序会错误地将连接设置为注定状态.

有关详细信息,请参阅KB 2605597

https://support.microsoft.com/kb/2605597


Has*_*eeb 10

我遇到了同样的问题,并通过在 web.config 文件中添加“连接时间”值来解决。找到 connectionStrings 并添加Connection Timeout=3600"

这是样本

  <connectionStrings>
    <add name="MyConn" providerName="System.Data.SqlClient" connectionString="Data Source=MySQLServer;Initial Catalog=MyDB;User ID=sa;Password=123;Connection Timeout=3600" />
  </connectionStrings>
Run Code Online (Sandbox Code Playgroud)

  • 这是以秒为单位的。参考[链接](https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.connectiontimeout?view=dotnet-plat-ext-6.0) (3认同)

ete*_*ity 9

也许它会对某些人有用.我遇到了同样的问题,在我的情况下,原因是SqlConnection被打开而没有放在我用循环调用大约2500次迭代的方法中.连接池已用尽.适当的处理解决了这个问题.


Sid*_*ted 7

您必须设置CommandTimeout属性.您可以在DbContext子类中设置CommandTimeout属性.

public partial class StudentDatabaseEntities : DbContext
{
    public StudentDatabaseEntities()
        : base("name=StudentDatabaseEntities")
    {
        this.Database.CommandTimeout = 180;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<StudentDbTable> StudentDbTables { get; set; }
}
Run Code Online (Sandbox Code Playgroud)


Vij*_*oje 6

我在3天左右遇到了相同的问题.我注意到我们的记录数量并不多,我们的高级开发人员在数据库中保留了2个图像和指纹.当我尝试获取这个十六进制值时需要很长时间,我计算执行我的程序的平均时间大约是38秒.默认的commandtimeout是30秒,因此它比运行我的存储过程所需的平均时间少.我将commandtimeout设置如下

cmd.CommandTimeout = 50
Run Code Online (Sandbox Code Playgroud)

并且它的工作正常,但有时如果你的查询超过50秒,它将提示相同的错误.


Dav*_*chs 5

默认超时为 15 秒,要更改它,0 是无限制的,任何其他数字都是秒数。

在代码中

using (SqlCommand sqlCmd = new SqlCommand(sqlQueryString, sqlConnection))
   {
      sqlCmd.CommandTimeout = 0; // 0 = give it as much time as it needs to complete
      ...
    }
Run Code Online (Sandbox Code Playgroud)

在您的 Web.Config 中,“命令超时 = 0;” 不超时,或低于 1 小时(3600 秒)

  <add name="ConnectionString" connectionString="Data Source=ServerName;User ID=UserName;Password=Password;Command Timeout=3600;" providerName="System.Data.SqlClient" />
Run Code Online (Sandbox Code Playgroud)

  • 这是两个不同的超时。您的第一个建议解决了这个问题。你的第二个只有在连接提供者支持的情况下才有效,而 SqlClient 不支持。无论如何,在生产中超时为 0 从来都不是一个好主意。30 秒是通常的默认值。 (4认同)

Mat*_*kan 5

如果您按照Startup.cs约定使用 ASP.NET Core,则可以像这样访问和设置查询命令超时选项:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextPool<MyDbContext>(_ =>
    {
        _.UseSqlServer(Configuration.GetConnectionString("MyConnectionString"), options => 
        {
            options.CommandTimeout(180); // 3 minutes
        });
    });
}
Run Code Online (Sandbox Code Playgroud)