超时已过期。在操作完成之前,超时时间已经过去或服务器未响应。该语句已终止。

412
我网站上有很多用户(每天20000-60000人次),这是一个移动文件下载站点。我可以远程访问我的服务器(Windows Server 2008-R2)。我之前收到过“服务器不可用”错误,但现在看到连接超时错误。我对此不熟悉 - 为什么会发生这种情况,如何修复它?
完整的错误信息如下:
Server Error in '/' Application. Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. [SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated.] System.Data.SqlClient.SqlConnection.OnError(SqlException exception, 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.ExecuteNonQuery() +327 NovinMedia.Data.DbObject.RunProcedure(String storedProcName, IDataParameter[] parameters, 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): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated.] System.Web.HttpApplicationFactory.EnsureAppStartCalledForIntegratedMode(HttpContext context, HttpApplication app) +4052053 System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +191 System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +352 System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +407 System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +375 [HttpException (0x80004005): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. The statement has been terminated.] System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +11686928 System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +141 System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +4863749
EDIT AFTER ANSWERS: 我在Global.asax中的Application_Start如下:
protected void Application_Start(object sender, EventArgs e)
{
    Application["OnlineUsers"] = 0;

    OnlineUsers.Update_SessionEnd_And_Online(
        DateTime.Now,
        false);

    AddTask("DoStuff", 10);
}

被调用的存储过程是:

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

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

  1. 使用 Application["OnlineUsers"] = 0;
  2. 另一种方法是使用数据库

所以,对于第二种方法,我在 Application_Start 中重置了所有在线用户。该表中有超过482,751条记录。


2
如此写道[默认为15秒] (http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.connectiontimeout.aspx) - V4Vendetta
1
最好进行根本原因分析,造成这种问题的原因有很多。最基本的是查询结构复杂。当我从表中提取存储为十六进制值的图像时,我遇到了相同的问题。 - Vijay Kumbhoje
除了上述原因,我还要补充一个:锁定超时:https://learn.microsoft.com/en-us/sql/t-sql/statements/set-lock-timeout-transact-sql 如果此线程等待锁定时间过长,则会根据上述文档超时。 - Herbert Yu
在服务中重新启动SQL Server解决了我的问题。 - xinthose
注意:此错误的另一个可能原因是,如果您在C#/VB.NET代码中使用事务,然后从事务内调用其他访问数据库的函数/子程序。解决方法是将db传递给嵌套的函数/子程序,以便它们被视为同一事务的一部分。(注意:理想情况下,我建议不要在应用程序代码中执行事务;而是在SQL代码中执行。) - Taraz
26个回答

453

看起来你的查询耗时比预期的长。通过查看堆栈跟踪和代码,你应该能够确定具体是哪个查询导致的。

这种超时可能有三种原因:

  1. 某处发生了死锁
  2. 数据库的统计信息和/或查询计划缓存不正确
  3. 查询过于复杂,需要进行调优

死锁可能很难修复,但很容易确定是否存在此问题。使用 Sql Server Management Studio 连接到数据库,在左侧面板右键单击服务器节点并选择 活动监视器。查看运行的进程。 通常大部分都是空闲或运行状态。当出现问题时,可以通过进程状态识别任何阻塞的进程。如果右键单击进程并选择 详细信息,它将显示进程执行的最后一个查询。

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

exec sp_updatestats

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

dbcc freeproccache

如果服务器负载过重,你不应该这样做,因为它会导致临时性的大量性能损失,因为当首次执行时,所有存储过程和查询都会重新编译。 然而,由于你说问题有时候发生,并且堆栈跟踪表明你的应用程序正在启动,我认为你正在运行一个仅在偶尔运行的查询。你可以通过强制SQL Server不重用上一个查询计划来更好地解决这个问题。请参阅此答案,了解如何操作。

我已经提到了第三个问题,但是您可以通过手动执行查询(例如使用Sql Server Management Studio)轻松确定是否需要对查询进行调整。如果查询花费太长时间才能完成,即使在重置统计信息后,您可能仍需要对其进行调整。如果需要帮助,请在新问题中发布精确的查询。


48
我也遇到了相同的错误,但是查询时间只有8秒...你提供的关于 exec sp_updatestats 的提示解决了我的问题。非常感谢! - nrod
3
解决这样的问题几乎从来不是调整超时时间或连接池大小的问题。您需要深入研究并找出根本原因。如果您需要帮助解决根本原因,可以发布自己的问题。 - Marnix van Valen
8
这绝不是一个死锁。它可能是由过度阻塞引起的,但死锁会在一秒钟内解决,并且会产生不同的错误。这可能是过度阻塞,但并不是死锁。 - Michael J Swart
1
我们确定这是一个命令超时而不是连接超时吗?"System.Data.SqlClient.SqlConnection.OnError" 对我来说表明存在连接问题。 - Mike W
1
@PrashantPimpale 这要看情况 如果您在生产环境中遇到严重问题,其中不正确的统计信息导致执行计划不良,则可以考虑更新统计信息。除非出现异常问题(如硬件故障),否则更新统计信息不会破坏您的数据库。这可能会导致查询速度变慢一段时间。最终,决定权在您手中。 - Marnix van Valen
显示剩余6条评论

197

在你运行存储过程的代码中,你应该有类似这样的内容:

SqlCommand c = new SqlCommand(...)
//...

添加这样一行代码:

c.CommandTimeout = 0;

这将等待足够的时间以完成操作。


184
你还应该知道,0值并不被推荐使用0值表示没有限制,在CommandTimeout中应避免使用它,因为尝试执行命令将无限等待。最好学习命令需要多长时间,并在需要时增加超时值。 - Otiel
9
我同意Otiel的观点,也对你的回答进行了点踩:如果将commandTimeout设置为0,你就没有给网络服务器从无响应的数据库服务器中恢复的机会。另外,当你达到默认的超时时间时,应该考虑问题的原因。在大多数情况下,修复查询而不是提高超时时间更为明智。 - Maarten Kieft
21
我不会陷入不推荐的陷阱。它对我和我的日常计划任务非常有用:无限超时并不会阻止进程在出现问题时完成并返回错误。简而言之,它只是让你允许一个查询在需要时完成,而不会因为没有为进程分配足够的时间而在以后遇到问题。您还可以通过多线程避免程序锁死。 - WonderWorker
2
如果你要传输数百万行数据,那么不设置这个选项是没有意义的。Otiel和BlackHawkDesign所说的话在这种情况下就不合适了。 - bluerubez
2
在20年的数据中心开发中,我从未需要过这样做。几乎总有一个相当简单的解决方案,可以提供更好的性能,并且不会创造一个机会让单个进程整天磨损数据库。绝大多数数据库性能问题可以调整到执行速度快几个数量级。也就是说,你等待3小时才能完成的那个进程,可能可以调整为3分钟甚至3秒钟。 - b_levitt
显示剩余2条评论

40
您可以设置SQL命令的CommandTimeout属性来允许长时间运行的SQL交易。
您可能还需要查看导致超时的SQL查询。

嗨,“或者你需要查看导致超时的SQL查询” -> 在SQL Server 2008中,我应该在哪里检查超时? - SilverLight
你可能需要测试被 DataLayer.OnlineUsers.Update_SessionEnd_And_Online 调用的存储过程,因为堆栈跟踪似乎指向它。将现有数据库复制到测试环境,传入必需的参数运行该存储过程,如果超过30秒完成,则出现超时。我假设你已经可以访问 SQL Server Management Studio。 - Kev Ritchie
是的,我可以访问SQL Server 2008。我应该尝试你的方法。 - SilverLight
如果你找到了引起问题的存储过程,你可以通过数据库调整顾问运行存储过程中包含的查询,该顾问会建议你是否需要任何索引等。链接在此处 http://msdn.microsoft.com/en-us/library/ms174202.aspx - Kev Ritchie

24

我曾经遇到过同样的问题,并通过在 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>

是秒还是毫秒? - MohammadHossein R
1
它以秒为单位。请参考 链接 - Haseeb
如果每个查询/事务需要一个小时的时间,那就太长了,也许理想情况下是15分钟。因此,60 * 15 = 900,具体取决于情况。 - toha

16

也许对于某些人会有所帮助。 我面临着相同的问题,在我的情况下,原因是在循环中调用的方法中,SqlConnection被打开但未被处理。 连接池已经耗尽。适当的处理解决了这个问题。


确切地说这样做就对了。我的问题在于我在不等待另一个线程上的方法完成就开始执行它们(因为用户不需要那个方法的结果,背景脚本)。没有使用“using”块进行处理,我就遇到了超时问题。使用“using”块似乎解决了这个问题。 - CularBytes
1
你是否遇到了连接池达到最大值而导致的超时错误或者超时时间已过但操作尚未完成,或者服务器无响应的错误?如果你收到了最大连接池数已达到的错误信息,那么有必要检查是否存在泄漏的连接。但是,我遇到的是服务器无响应的错误。 - Jeeva Subburaj

13

虽然之前的回答都解决了这个问题,但并没有覆盖所有情况。

微软已经承认了这个问题,并在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)

您可能需要更新您的.NET组件。

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

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

有关详细信息,请参见KB 2605597。

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


13

你需要设置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; }
}

10

我曾遇到同样的问题并花了大约三天时间去解决它。我发现我们的记录数不多,我们的高级开发人员会将两个图像和指纹存储在数据库中。当我尝试获取这些十六进制值时,它需要很长时间,我计算执行我的过程的平均时间约为38秒。默认的commandtimeout是30秒,所以它小于运行我的存储过程所需的平均时间。我像下面这样设置了我的commandtimeout

cmd.CommandTimeout = 50

现在它可以正常工作,但是有时候如果您的查询花费超过50秒,它会提示相同的错误。


8
如果您正在使用ASP.NET Core和Startup.cs约定,则可以通过以下方式访问并设置查询命令超时选项:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextPool<MyDbContext>(_ =>
    {
        _.UseSqlServer(Configuration.GetConnectionString("MyConnectionString"), options => 
        {
            options.CommandTimeout(180); // 3 minutes
        });
    });
}

4
我最近遇到了这个错误,经过简要调查,发现原因是我们的数据库所在磁盘空间不足(小于1GB)。
一旦我将数据库文件(.mdf和.ldf)移动到同一服务器上另一个磁盘(具有更多的空间),运行查询的同一页(超时)在三秒内加载完成。
在尝试解决此错误时,还有一件事需要调查,那就是数据库日志文件的大小。您的日志文件可能需要缩小。

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