偶尔出现SqlException: Timeout expired

Posted

技术标签:

【中文标题】偶尔出现SqlException: Timeout expired【英文标题】:Occasionally Getting SqlException: Timeout expired 【发布时间】:2013-05-30 19:20:54 【问题描述】:

我的服务器上正在运行应用程序。这个应用程序的问题是,每天我得到近 10-20,System.Data.SqlClient.SqlException Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding 只有我的一个 SP。这是我的SP,

            ALTER PROCEDURE [dbo].[Insertorupdatedevicecatalog] 
                            (@OS                NVARCHAR(50) 
                            ,@UniqueID          VARCHAR(500)
                            ,@Longitude         FLOAT 
                            ,@Latitude          FLOAT
                            ,@Culture           VARCHAR(10)
                            ,@Other             NVARCHAR(200)
                            ,@IPAddress         VARCHAR(50)
                            ,@NativeDeviceID    VARCHAR(50))
            AS 
            BEGIN 

                DECLARE @OldUniqueID VARCHAR(500) = '-1';
                SELECT @OldUniqueID = [UniqueID] FROM DeviceCatalog WHERE (@NativeDeviceID != '' AND [NativeDeviceID] = @NativeDeviceID);

                BEGIN TRANSACTION [Tran1]
                    BEGIN TRY
                        IF EXISTS(SELECT 1 FROM DeviceCatalog WHERE [UniqueID] = @UniqueID) 
                        BEGIN 
                            UPDATE  DeviceCatalog 
                               SET  [OS] = @OS
                                   ,[Location] = geography::STGeomFromText('POINT(' + CONVERT(VARCHAR(100 ), @Longitude) + ' ' + CONVERT(VARCHAR(100), @Latitude) + ')', 4326)
                                   ,[Culture] = @Culture
                                   ,[Other] = @Other
                                   ,[Lastmodifieddate] = Getdate()
                                   ,[IPAddress] = @IPAddress
                            WHERE   [UniqueID] = @UniqueID;
                        END
                        ELSE 
                        BEGIN
                            INSERT INTO DeviceCatalog
                                        ([OS]
                                        ,[UniqueID]
                                        ,[Location] 
                                        ,[Culture] 
                                        ,[Other]
                                        ,[IPAddress]
                                        ,[NativeDeviceID])
                                VALUES  (@OS
                                        ,@UniqueID
                                        ,geography::STGeomFromText('POINT(' + CONVERT(VARCHAR(100) ,@Longitude) + ' ' + CONVERT(VARCHAR(100), @Latitude) + ')', 4326) 
                                        ,@Culture
                                        ,@Other
                                        ,@IPAddress
                                        ,@NativeDeviceID);
                                IF(@OldUniqueID != '-1' AND @OldUniqueID != @UniqueID)
                                BEGIN
                                    EXEC DeleteOldDevice @OldUniqueID, @UniqueID;
                                END
                        END
                        COMMIT TRANSACTION [Tran1];
                    END TRY
                    BEGIN CATCH
                        ROLLBACK TRANSACTION [Tran1];
                        DECLARE @ErrorNumber nchar(5), @ErrorMessage nvarchar(2048);
                        SELECT
                            @ErrorNumber = RIGHT('00000' + ERROR_NUMBER(), 5),
                            @ErrorMessage = @ErrorNumber + ' ' + ERROR_MESSAGE();
                        RAISERROR (@ErrorMessage, 16, 1);
                    END CATCH
            END

这个SP有什么问题吗?为什么我只在这个 SP 中得到超时异常?这是堆栈跟踪,

System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at App.Classes.DBLayer.Execute(SqlCommand command, Boolean executeNonQuery)
   at App.Helpers.SQLHelper.GetResult(List`1 parameters, Boolean storedProcedure, String commandText, ResultType type)
   at App.Helpers.SQLHelper.ExecuteNonQuery(List`1 parameters, Boolean storedProcedure, String commandText)
   at App.Services.DeviceCatalogService.InsertOrUpdateDeviceCatalog(DeviceCatalog deviceCataLog)
   at WebApplication1.Handlers.RegisterDevice.ProcessRequest(HttpContext context)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

【问题讨论】:

为什么?因为执行时间太长了。优化它。无法用提供的详细信息回答这个问题。投票结束。 您是否使用 msdn.microsoft.com/en-us/library/… CommandTimeout 获得了解决方案? 【参考方案1】:

您需要在服务器端对此进行调查,以了解执行超时的原因。注意服务器没有超时,超时是SqlCommand.CommandTimeout上默认的30秒造成的。

Waits and Queues 是一个很好的资源,它是一种诊断 SQL Server 性能瓶颈的方法。根据超时的实际原因,可以采取适当的措施。您必须首先确定您是在处理缓慢执行(一个糟糕的计划)还是阻塞。

如果我大胆猜测,我会说IF EXISTS... UPDATE 的不健康模式是根本原因。这种模式是不正确的,会导致并发下失败。同时执行IF EXISTS 的两个并发事务都将得出相同的结论,并且 尝试INSERTUPDATE。根据数据库中现有的约束,您最终可能会出现死锁(幸运的情况)或丢失的写入(不幸的情况)。然而,只有适当的调查才能揭示真正的根本原因。可能是完全不同的东西,比如auto-growth events。

您的过程也错误地处理了 CATCH 块。您必须始终检查XACT_STATE(),因为在您的 CATCH 块运行时事务可能已经回滚。也不清楚您对命名事务的期望,这是我经常看到的一个常见错误,与混淆命名事务和保存点有关。有关正确的模式,请参阅Exception Handling and Nested Transactions。

编辑

这是一种可能的调查方法:

    将相关的CommandTimeout 更改为0(即无限)。 启用blocked process threshold,设置为30秒(前CommandTimeout) 在 Profiler 中监视 Blocked Process Report Event 开始您的工作量 查看 Profiler 是否生成任何报告事件。如果是这样,他们会查明原因。

如果超时是由阻塞引起的,那么每次您遇到超时时,这些操作都会导致“阻塞进程报告”事件。您的应用程序将继续等待,直到阻塞被移除,如果阻塞是由 live-lock 引起的,那么它将永远等待。

【讨论】:

查询的慢部分可能在任何部分。根本原因可能是任何事情。我认为这个问题无法回答。 +1 @usr,我有很多广泛而大的查询不会抛出这个错误,只有这个 SQL。我相信这个SP有问题。我认为执行是插入或更新没有什么特别的。数据库中没有索引,该表仅包含 800 条记录。你还需要什么? IF EXISTS ... UPDATE 替代:MERGE。您必须在 [UniqueID] 上有一个(聚集的?)索引(是的,即使在 VARCHAR(500) 也是如此)。 另外,检查一下how to use sp_whoisactive @RemusRusanu 完成见***.com/questions/17039925/…【参考方案2】:

将此行添加到您的连接字符串:

Connect Timeout=200; pooling='true'; Max Pool Size=200

你也可以设置myCom.CommandTimeout = 200

如果存在大量数据,您还可以将超时秒数从 200 秒增加到 600 秒。

也在 web.config 中编辑它。

关注THIS 文档。

【讨论】:

我认为他是说程序耗时太长是问题所在,增加超时并不能真正解决问题。 增加超时可能是一个有效的解决方案,尤其是考虑到 OP 显然不是查询调优方面的专家。然而,这是一个显而易见的解决方案。 虽然它的解决方案很明显,但我认为,OP 还没有尝试过。因为在那之后我不认为他会发布这个问题。 不,这在正常情况下也需要毫秒。【参考方案3】:

这可能是由于参数嗅探而发生的。所以只需使用在存储过程中声明的局部变量。并适当地使用它们。

声明@InVar1 ...

.....

其中条件=@Invar1

【讨论】:

【参考方案4】:

也许 OPTIMIZE FORWITH RECOMPILE 提示可以解决 SQL 异常超时问题。

本文介绍了如何实现它并解释了“参数嗅探”问题:

https://blogs.msdn.microsoft.com/robinlester/2016/08/10/improving-query-performance-with-option-recompile-constant-folding-and-avoiding-parameter-sniffing-issues/

【讨论】:

以上是关于偶尔出现SqlException: Timeout expired的主要内容,如果未能解决你的问题,请参考以下文章

偶尔获取SqlException:超时已过期

Spring Batch 无法获取 last_insert_id();嵌套异常是 java.sql.SQLException: Lock wait timeout exceeded;

SqlException:ConnectionTimeout Expired. The timeout period elapsed during the post-login phase

keepalive timeout

Jedis连接redis偶尔connection timeout

9. Lock wait timeout exceeded