偶尔获取SqlException:超时已过期

use*_*567 20 sql sql-server asp.net ado.net sql-server-2012

我在我的服务器上运行了应用程序.这个应用程序的问题是每天我得到近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
Run Code Online (Sandbox Code Playgroud)

这个SP有什么问题吗?为什么我只在此SP中获得超时异常?这是Stack Trace,

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)
Run Code Online (Sandbox Code Playgroud)

Rem*_*anu 26

您需要在服务器端对此进行调查,以了解执行超时的原因.请注意,服务器没有超时,超时是由默认的30秒开启引起的SqlCommand.CommandTimeout.

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

如果我冒险猜测,我会说不健康的模式IF EXISTS... UPDATE是根本原因.此模式不正确,将导致并发失败.同时执行两个并发事务IF EXISTS将得出相同的结论并且两者都尝试INSERTUPDATE.根据数据库中的退出约束,您最终可能会出现死锁(幸运案例)或丢失写入(不幸的情况).但是,只有适当的调查才能揭示实际的根本原因.可能是完全不同的东西,比如自动增长事件.

您的过程也错误地处理CATCH块.您必须始终检查,XACT_STATE()因为在您的CATCH块运行时,事务可能已经回滚.还不清楚您对命名事务的期望是什么,这是我经常看到的常见错误,通常与使用保存点混淆命名事务相关联.有关正确的模式,请参阅异常处理和嵌套事务.

编辑

以下是调查此问题的可能方法:

  1. 将相关更改CommandTimeout为0(即无限).
  2. 启用blocked process threshold,将其设置为30秒(前CommandTimeout)
  3. 在Profiler中监视阻止的进程报告事件
  4. 开始你的工作量
  5. 查看Profiler是否生成任何报告事件.如果是这样,他们将查明原因.

如果超时是由阻塞引起的,那么每次超时都会导致"阻止进程报告"事件.您的应用程序将继续等待,直到阻止被删除,如果阻塞是由实时锁定引起的,那么它将永远等待.


Fre*_*cer 8

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

Connect Timeout=200; pooling='true'; Max Pool Size=200
Run Code Online (Sandbox Code Playgroud)

您可以设置myCom.CommandTimeout = 200

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

也可以在web.config中编辑它.

按照这个文件.

  • 我认为他说过程耗时太长是问题,增加超时并没有真正解决问题. (6认同)
  • 增加超时可能是一个有效的解决方案,特别是考虑到OP显然不是查询调优的专家.但这是一个明显的解决方案. (2认同)