Иногда Получение 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)
Ответы
Ответ 1
Вам нужно исследовать это на стороне сервера, чтобы понять, почему это время исполнения. Обратите внимание, что сервер не имеет таймаута, таймаут вызван по умолчанию 30 секунд на SqlCommand.CommandTimeout
.
Хорошим ресурсом является Waits and Queues, который является методологией для диагностики узких мест производительности с SQL Server. Исходя из фактической причины таймаута, можно предпринять правильное действие. Вы должны прежде всего установить, имеете ли вы дело с медленным выполнением (плохим планом) или блокировкой.
Если я рискну предположить, я бы сказал, что нездоровая модель IF EXISTS... UPDATE
является основной причиной. Этот шаблон неверен и приведет к сбоям в concurrency. Две одновременные транзакции, выполняющие IF EXISTS
, одновременно достигнут одного и того же вывода и обе попытки выполнить INSERT
или UPDATE
. В зависимости от выходных ограничений в базе данных вы можете оказаться в тупике (счастливый случай) или с потерянной записью (неудачный случай). Однако только правильное расследование выявило бы основную причину. Может быть что-то совершенно другое, например события автоматического роста.
Ваша процедура также неправильно обрабатывает блок CATCH. Вы должны всегда проверять XACT_STATE()
, потому что транзакция может быть отброшена к тому моменту, когда выполняется ваш блок CATCH. Также непонятно, что вы ожидаете от именования транзакции, это распространенная ошибка, которую я вижу часто связанную с запутыванием названных транзакций с помощью точек сохранения. Для правильной картины см. Обработка исключений и вложенные транзакции.
Edit
Вот возможный способ исследовать это:
Эти действия будут вызывать событие "заблокированный процесс" каждый раз, когда вы получили таймаут, если таймаут был причиной блокировки. Приложение будет продолжать ждать, пока блокировка не будет удалена, если блокировка вызвана live-lock, тогда она будет ждать всегда.
Ответ 2
Добавьте эту строку в строку подключения:
Connect Timeout=200; pooling='true'; Max Pool Size=200
Вы можете установить myCom.CommandTimeout = 200
также
Если имеется большое количество данных, вы также можете увеличить время ожидания от 200 до 600 секунд.
Измените это и в web.config.
Следуйте ЭТО doccument.
Ответ 3
Это может произойти из-за sniffing параметра. Поэтому просто используйте локальные переменные, объявленные в хранимой процедуре. и использовать их соответствующим образом.
Объявить @InVar1...
.....
где условие = @Invar1