【问题标题】:SQL server timeouts for some commands for a while just after restoring刚恢复后,某些命令的 SQL 服务器超时一段时间
【发布时间】:2015-05-19 15:42:23
【问题描述】:

我们在 asp.net mvc 中有一个使用 EF6 和 SQL Server 2012 的大型 Web 应用程序。

我们有两个环境:登台和生产。

每次发布​​时,我们首先部署完全相同的代码来暂存和恢复服务器上的生产数据库以进行测试。这对我们一直有效。

现在,当我们将生产数据库恢复到登台服务器时,我们会在某些命令上遇到一些超时。奇怪的是,几个小时过去了,我们就不再超时了。


这是其中一个超时的堆栈跟踪:

[Win32Exception (0x80004005): The wait operation timed out]

[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, Action`1 wrapCloseInAction) +388
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) +688
   System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) +4403
   System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() +82
   System.Data.SqlClient.SqlDataReader.get_MetaData() +135
   System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +6664141
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite) +6666008
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) +577
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +107
   System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +288
   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +180
   Glimpse.Ado.AlternateType.GlimpseDbCommand.ExecuteDbDataReader(CommandBehavior behavior) +847
   System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch(Func`1 operation, TInterceptionContext interceptionContext, Action`1 executing, Action`1 executed) +72
   System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext) +306
   System.Data.Entity.Core.Mapping.Update.Internal.DynamicUpdateCommand.Execute(Dictionary`2 identifierValues, List`1 generatedValues) +417
   System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() +218

[UpdateException: An error occurred while updating the entries. See the inner exception for details.]
   System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update() +537
   System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction(Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) +627
   System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy) +212
   System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Func`1 operation) +263
   System.Data.Entity.Core.Objects.ObjectContext.SaveChanges(SaveOptions options) +262
   System.Data.Entity.Internal.InternalContext.SaveChanges() +218

[DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.]
   System.Data.Entity.Internal.InternalContext.SaveChanges() +291
   *******.Services.DbTransaction.TransactionManager.SaveChanges() in c:\BuildAgent\work\c357fed3de014622\Source\Services\*******.Services\*******.Services\DbTransaction\TransactionManager.cs:28
   System.Web.Mvc.Async.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41() +112
   System.Web.Mvc.Async.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41() +452
   System.Web.Mvc.Async.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41() +452
   System.Web.Mvc.Async.<>c__DisplayClass48.<InvokeActionMethodFilterAsynchronouslyRecursive>b__41() +452
   System.Web.Mvc.Async.<>c__DisplayClass33.<BeginInvokeActionMethodWithFilters>b__32(IAsyncResult asyncResult) +15
   System.Web.Mvc.Async.<>c__DisplayClass2b.<BeginInvokeAction>b__1c() +37
   System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +241
   System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +19
   System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288

如果请求一切顺利,我们有一个动作过滤器调用context.SaveChanges() 方法(因此我们不必在每个动作中手动执行此操作)。这就是为什么在堆栈跟踪上没有任何操作,当操作完成时,它会在 SaveChanges() 调用上超时。

这个请求发生了很多事情,这就是为什么我没有显示代码,我们正在做通常的事情:更新一些行,插入新行等。那里有一些复杂的命令,但还不够复杂数据库超时。当我们在具有相同生产数据库的开发机器上运行代码时,它运行正常。

奇怪的是它会在几个小时后停止超时。但我们不能冒险去生产。

现在,我知道您不可能仅凭提供的信息就给我解决方案。但我想知道一些提示、指示、建议、在哪里查看、检查什么等。

编辑

我们的服务器有 12GB 的 RAM 和 Intel Xeon E5-2680 @ 2.80GHz。

我们的网站是唯一在那里运行的东西。

我们的数据库小于 4GB

而且我们的开发机器不会超时。

【问题讨论】:

    标签: sql-server asp.net-mvc entity-framework


    【解决方案1】:

    我们终于发现了发生了什么:

    我们有一个在迁移后执行的种子方法,该方法打开了与数据库的连接,并查询了一些需要永远响应的外部服务,它运行了几个小时,并且这些查询阻塞了插入命令。

    感谢Zdravko's suggestion,我们能够找到问题。

    我们运行 exec sp_who2 并发现 insert 被种子方法的 select 查询阻止。

    所以,如果有人遇到类似问题:帮助我们的是使用 sql 分析器并过滤比 30 sec 更长的查询来查找有问题的查询,并使用 exec sp_who2 检查是否有人阻止它们。

    【讨论】:

      【解决方案2】:

      超时很可能是由于 SQL Server 重建索引和恢复后运行的其他维护作业。这些可能会在更大的数据库上花费大量时间。例如,全文搜索索引的构建时间特别长...

      【讨论】:

      • 喜欢几个小时?我的意思是,上次是 6 个小时,我们甚至跑了 exec sp_updatestats
      • 嗯,这一切都取决于...你的数据库有多大,服务器上还有什么(以及服务器首先有多强大)
      • 选取一个超时的查询并查看执行计划。然后等待 6h 并再次检查执行计划。我敢打赌它会有所不同,第二次使用不同的索引。
      • 我如何知道导致超时的确切查询?
      • 您可以运行 sql 分析器并捕获所有耗时超过 30 秒的查询。或者,您可以从 EF 捕获异常并记录(例如记录到事件日志)触发异常的查询。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 2021-10-07
      • 2015-05-01
      • 2023-03-18
      • 1970-01-01
      相关资源
      最近更新 更多