it-swarm.com.de

Gelegentlich SqlException abrufen: Zeitüberschreitung abgelaufen

Ich habe eine Anwendung auf meinem Server. Das Problem bei dieser Anwendung ist, dass ich täglich fast 10-20 System.Data.SqlClient.SqlException Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding nur einen meiner SP bekomme. Hier ist mein 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

Gibt es ein Problem mit diesem SP? Warum erhalte ich nur in diesem SP eine Timeout-Ausnahme? Hier ist die Stapelverfolgung,

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)
19
user960567

Sie müssen dies auf der Serverseite untersuchen, um zu verstehen, warum die Ausführung abläuft. Beachten Sie, dass der Server kein Timeout hat. Das Timeout wird durch die Standardeinstellung von 30 Sekunden für SqlCommand.CommandTimeout verursacht.

Eine gute Ressource ist Waits and Queues , eine Methode zur Diagnose von Leistungsengpässen mit SQL Server. Ausgehend von der tatsächlichen Ursache des Timeouts können geeignete Maßnahmen ergriffen werden. Sie müssen zunächst feststellen, ob Sie mit langsamer Ausführung (einem schlechten Plan) oder mit Blockierungen zu tun haben.

Wenn ich eine Vermutung wagen würde, würde ich sagen, dass das ungesunde Muster von IF EXISTS... UPDATE die Hauptursache ist. Dieses Muster ist falsch und führt zu Fehlern bei der Parallelität. Zwei gleichzeitige Transaktionen, die den IF EXISTS gleichzeitig ausführen, werden zu derselben Schlussfolgerung gelangen und beide versuchen, INSERT oder UPDATE zu versuchen. Abhängig von den bestehenden Einschränkungen in der Datenbank können Sie mit einem Deadlock (dem glücklichen Fall) oder einem verlorenen Schreibvorgang (dem unglücklichen Fall) enden. Nur eine ordnungsgemäße Untersuchung würde jedoch die tatsächliche Ursache aufdecken. Könnte etwas völlig anderes sein, wie automatische Wachstumsereignisse .

Ihre Prozedur behandelt den CATCH-Block auch falsch. Sie müssen immer das XACT_STATE() überprüfen, da die Transaktion möglicherweise bereits rückgängig gemacht wird, wenn Ihr CATCH-Block ausgeführt wird. Es ist auch nicht klar, was Sie von der Benennung der Transaktion erwarten. Dies ist ein häufiger Fehler, der häufig mit dem Verwechseln von benannten Transaktionen mit Sicherungspunkten in Verbindung gebracht wird. Ein korrektes Muster finden Sie unter Ausnahmebehandlung und geschachtelte Transaktionen .

Bearbeiten

Hier ist ein möglicher Weg, dies zu untersuchen:

  1. Ändern Sie das relevante CommandTimeout in 0 (dh unendlich).
  2. Aktivieren Sie das blocked process threshold und setzen Sie es auf 30 Sekunden (der vorherige CommandTimeout).
  3. Überwachen Sie im Profiler auf Blockiertes Prozessberichtereignis
  4. Starten Sie Ihre Workload
  5. Prüfen Sie, ob der Profiler Berichtsereignisse generiert. Wenn dies der Fall ist, ermitteln sie die Ursache.

Diese Aktionen verursachen jedes Mal, wenn Sie ein Timeout erhalten würden, ein Ereignis zum Blockieren von Prozessberichten, wenn das Timeout durch Blockieren verursacht wurde. Ihre Anwendung wartet weiter, bis die Blockierung aufgehoben ist. Wenn die Blockierung durch Live-Lock verursacht wird, wird sie für immer warten.

25
Remus Rusanu

Fügen Sie diese Zeile zu Ihrer Verbindungszeichenfolge hinzu:

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

Sie können auch myCom.CommandTimeout = 200 einstellen

Wenn eine große Anzahl von Daten vorhanden ist, können Sie die Timeout-Sekunden auch von 200 auf 600 Sekunden erhöhen.

Bearbeiten Sie dies auch in web.config.

Folgen Sie DIESEM Dokument.

8
Freelancer

Dies kann aufgrund von Parameter-Sniffing geschehen. Verwenden Sie also nur lokale Variablen, die in der gespeicherten proc deklariert sind. und verwenden Sie sie entsprechend.

@ InVar1 deklarieren ...

.....

dabei ist Bedingung = @ Invar1

1
Rahul Vadhan

Möglicherweise lösen die Hinweise OPTIMIZE FOR oder WITH RECOMPILE das SQL-Ausnahme-Timeout-Problem. 

Dieser Artikel beschreibt, wie er implementiert wird, und erläutert die Probleme beim "Parameter-Sniffing":

https://blogs.msdn.Microsoft.com/robinlester/2016/08/10/improving-query-performance-mit-option-recompile-constant-folding-und-avoiding-parameter-sniffing-issues/

1
Edu Pelais