Иногда Получение SqlException: время ожидания истекло - программирование
Подтвердить что ты не робот

Иногда Получение SqlException: время ожидания истекло

У меня есть приложение, запущенное на моем сервере. Проблема с этим приложением заключается в том, что ежедневно я получаю почти 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? Почему я получаю исключение Timeout только в этом 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)
4b9b3361

Ответ 1

Вам нужно исследовать это на стороне сервера, чтобы понять, почему это время исполнения. Обратите внимание, что сервер не имеет таймаута, таймаут вызван по умолчанию 30 секунд на SqlCommand.CommandTimeout.

Хорошим ресурсом является Waits and Queues, который является методологией для диагностики узких мест производительности с SQL Server. Исходя из фактической причины таймаута, можно предпринять правильное действие. Вы должны прежде всего установить, имеете ли вы дело с медленным выполнением (плохим планом) или блокировкой.

Если я рискну предположить, я бы сказал, что нездоровая модель IF EXISTS... UPDATE является основной причиной. Этот шаблон неверен и приведет к сбоям в concurrency. Две одновременные транзакции, выполняющие IF EXISTS, одновременно достигнут одного и того же вывода и обе попытки выполнить INSERT или UPDATE. В зависимости от выходных ограничений в базе данных вы можете оказаться в тупике (счастливый случай) или с потерянной записью (неудачный случай). Однако только правильное расследование выявило бы основную причину. Может быть что-то совершенно другое, например события автоматического роста.

Ваша процедура также неправильно обрабатывает блок CATCH. Вы должны всегда проверять XACT_STATE(), потому что транзакция может быть отброшена к тому моменту, когда выполняется ваш блок CATCH. Также непонятно, что вы ожидаете от именования транзакции, это распространенная ошибка, которую я вижу часто связанную с запутыванием названных транзакций с помощью точек сохранения. Для правильной картины см. Обработка исключений и вложенные транзакции.

Edit

Вот возможный способ исследовать это:

  • Измените соответствующий CommandTimeout на 0 (т.е. бесконечный).
  • Включите blocked process threshold, установите его на 30 секунд (прежнее CommandTimeout)
  • Монитор в профайлере для Заблокированное событие отчета процесса
  • Начать рабочую нагрузку
  • Посмотрите, создает ли Profiler какие-либо события отчета. Если это так, они будут определять причину.

Эти действия будут вызывать событие "заблокированный процесс" каждый раз, когда вы получили таймаут, если таймаут был причиной блокировки. Приложение будет продолжать ждать, пока блокировка не будет удалена, если блокировка вызвана live-lock, тогда она будет ждать всегда.

Ответ 2

Добавьте эту строку в строку подключения:

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

Вы можете установить myCom.CommandTimeout = 200 также

Если имеется большое количество данных, вы также можете увеличить время ожидания от 200 до 600 секунд.

Измените это и в web.config.

Следуйте ЭТО doccument.

Ответ 3

Это может произойти из-за sniffing параметра. Поэтому просто используйте локальные переменные, объявленные в хранимой процедуре. и использовать их соответствующим образом.

Объявить @InVar1...

.....

где условие = @Invar1