2013-06-04 2 views
16

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

  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) 
+1

Почему? Потому что выполнение заняло слишком много времени. Оптимизируйте его. Невозможно ответить на этот вопрос с предоставленной информацией. Голосование закрывается. – usr

+0

Вы получили решение, используя *** https: //msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx*** 'CommandTimeout'? – Kiquenet

ответ

20

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

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

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

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

Редактировать

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

  1. Измените отношение CommandTimeout к 0 (т. Е бесконечна).
  2. Включите blocked process threshold, установите его на 30 секунд (бывший CommandTimeout)
  3. Monitor в Profiler для Blocked Process Report Event
  4. Начало рабочей нагрузки
  5. Смотрите, если Profiler производит каких-либо событий отчета. Если это произойдет, они будут точно определять причину.

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

+1

Медленная часть запроса может быть в любой части. Коренной причиной может быть что угодно. Я считаю этот вопрос неопровержимым. +1 – usr

+0

@usr, у меня много обширных и больших запросов, которые не бросают эту ошибку, только этот SQL. Я считаю, что в этом SP есть что-то не так. Я думаю, что выполнение вставляет или обновляет ничего особенного. В базе данных нет индексации, а таблица содержит только 800 записей. Что еще нужно вам? – user960567

+0

'IF EXISTS ... UPDATE': [' MERGE'] (http://technet.microsoft.com/en-us/library/bb510625.aspx). У вас должен быть (сгруппированный?) Индекс на '[UniqueID]' (да, даже на 'VARCHAR (500)'). –

6

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

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

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

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

Редактировать это также в web.config.

THIS doccument.

+3

-1 затем измените его 500, затем на 1000 и так далее ... –

+0

@RemusRusanu какой ??? Я не понял ваш комментарий. – Freelancer

+5

Я думаю, что он говорит, что слишком длительная процедура - проблема, и увеличение тайм-аута на самом деле не решает проблему. –

1

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

Declare @ InVar1 ...

.....

где состояние = @ Invar1

0

Может быть ОПТИМИЗАЦИЯ ДЛЯ или С RECOMPILE намеков решить проблему исключения тайм-аута SQL ,

Эта статья преподает, как реализовать это и объясняет «параметр нюхают» вопросы:

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

Смежные вопросы