Probleme beim Sperren und Wachstum der ASPState-Datenbank

8

Wir verwenden eine ASPState-Datenbank, um den .NET-Sitzungsstatus in einem SQL Server 2005-Cluster beizubehalten. In Spitzenzeiten sehen wir ein merkwürdiges Verhalten

  • Der DeleteExpiredSessions-Prozess wird jede Minute über einen Agentenjob ausgeführt. Manchmal dauert es viele Minuten, bis dieser Job abgelaufene Sitzungen ausgeführt und gelöscht hat

  • Anforderungen von der Anwendung an die ASPState-Datenbank sind sehr langsam. Ich glaube, das liegt daran, dass das DeleteExpiredSessions-Verfahren exklusive Sperren auf dem Tisch hält

Code:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[DeleteExpiredSessions]
AS
        SET NOCOUNT ON
        SET DEADLOCK_PRIORITY LOW 

        DECLARE @now datetime
        SET @now = GETUTCDATE() 

        DECLARE @tblExpiredSessions TABLE
        (
            SessionID nvarchar(88) NOT NULL PRIMARY KEY
        )

        INSERT INTO @tblExpiredSessions (SessionID)
            SELECT SessionID
            FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED)
            WHERE Expires < @now

        --EXPIRED SESSION LOGGING 
        /*
        DECLARE @ExpiredSessionCount Int;
        SELECT @ExpiredSessionCount = COUNT(SessionID) 
        FROM @tblExpiredSessions;
        */


        IF @@ROWCOUNT <> 0 
        BEGIN 
            DECLARE ExpiredSessionCursor CURSOR LOCAL FORWARD_ONLY READ_ONLY
            FOR SELECT SessionID FROM @tblExpiredSessions ORDER BY CHECKSUM(NEWID())

            DECLARE @SessionID nvarchar(88)

            OPEN ExpiredSessionCursor

            FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID

            WHILE @@FETCH_STATUS = 0 
                BEGIN
                    DELETE FROM [ASPState].dbo.ASPStateTempSessions WHERE SessionID = @SessionID AND Expires < @now
                    FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID
                END

            CLOSE ExpiredSessionCursor

            DEALLOCATE ExpiredSessionCursor

        END 

        --EXPIRED SESSION LOGGING
        /*
        BEGIN TRY
             INSERT INTO DeleteExpiredSessionLog(RunStart, RunEnd, ExpiredSessionsDeleted)
             VALUES (@now, GETUTCDATE(), @ExpiredSessionCount);
        END TRY
        BEGIN CATCH
             --SWALLOW ANY EXCEPTION
        END CATCH;
        */


    RETURN 0                          
  • Die Protokolldatei füllt sich und erzwingt in einigen Fällen das automatische Wachstum, obwohl sich die Datenbank in einer einfachen Wiederherstellung befindet

Darüber hinaus werden in einer Ablaufverfolgung mehrere Anforderungen für dieselbe Sitzung schnell hintereinander angezeigt. Zum Beispiel exec dbo.TempResetTimeout @id=N'32gghltsuoesnvlzbehchp2m2014c0f1'14 Mal in <1 Sekunde, also wundern wir uns über diese Ursache oder Überlastung, sind uns aber nicht sicher, woher dieses Verhalten stammt.

Anregungen oder Erklärungen zu diesem Verhalten sind willkommen.

zurückhaltendKoala
quelle
Hintergrundinformationen zum Sitzungsstatus finden Sie hier: msdn.microsoft.com/en-us/library/aa478952.aspx
reticentKoala
Wir haben die folgende Empfehlung umgesetzt: aspalliance.com/articleViewer.aspx?aId=1184&pId=-1
reticentKoala
Ah, ich verstehe, das ist ein Ersatz. Haben Sie das Original ersetzt, weil Sie damals ein Problem hatten oder weil jemand im Internet dies gesagt hat? Ich würde vorschlagen, zum Original zurückzukehren, um festzustellen, ob das Symptom besser oder schlechter wird. Um mögliche Blockierungen zu reduzieren , können Sie auch Folgendes tunSELECT 1; WHILE @@ROWCOUNT <> 0 BEGIN DELETE TOP (10) ... END
Aaron Bertrand
Da die Prozedur zu Stoßzeiten> 1 Minute lang ausgeführt wird, besteht die Gefahr, dass 2 Kopien des Prozesses versuchen, dieselbe Zeile zu löschen. Die Bestellung durch NEWID verringert die Wahrscheinlichkeit dafür.
ReticentKoala
2
Ich habe einen Blog-Beitrag geschrieben, in dem einige mögliche Verbesserungen behandelt wurden, um die Auswirkungen von ASPState weniger spürbar zu machen: sqlperformance.com/2013/01/t-sql-queries/optimize-aspstate
Aaron Bertrand

Antworten:

5

Ich vermute, Sie haben Gregs Ersetzungsverfahren als vorbeugende Optimierung implementiert. Der Ansatz, jeweils eine Zeile zu verwenden, beschränkt das Sperren auf eine einzelne Zeile, aber es wird viel länger dauern - insbesondere, wenn Sie SQL Server zwingen, Zeilen in zufälliger Reihenfolge anzugreifen.

Mein Vorschlag wäre, zum ursprünglichen Verfahren zurückzukehren:

ALTER PROCEDURE dbo.DeleteExpiredSessions
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @now DATETIME;
  SET @now = GETUTCDATE();

  DELETE ASPState..ASPStateTempSessions 
    WHERE Expires < @now;
END
GO

Wenn Sie feststellen, dass dies aufgrund der vorgenommenen Sperren zu einem Leistungsproblem wird, können Sie dies aufteilen und sogar die Auswirkungen auf die Protokolle verringern, indem Sie Folgendes verwenden:

ALTER PROCEDURE dbo.DeleteExpiredSessions
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @now DATETIME, @c INT;
  SELECT @now = GETUTCDATE(), @c = 1;

  BEGIN TRANSACTION;

  WHILE @c <> 0
  BEGIN
    ;WITH x AS 
    (
      SELECT TOP (1000) SessionId
        FROM dbo.ASPStateTempSessions
        WHERE Expires < @now
        ORDER BY SessionId
    ) 
    DELETE x;

    SET @c = @@ROWCOUNT;

    IF @@TRANCOUNT = 1
    BEGIN
      COMMIT TRANSACTION;
      BEGIN TRANSACTION;
    END
  END

  IF @@TRANCOUNT = 1
  BEGIN
    COMMIT TRANSACTION;
  END
END
GO

Dies wird meiner Meinung nach viel besser sein, als einen zufälligen Cursor zu verwenden, um jeweils eine Zeile zu löschen. Sie können den Wert TOP (1000)basierend auf der tatsächlichen Beobachtung anpassen .

Ein paar andere Ideen, die helfen könnten:

(a) Setzen Sie das Wiederherstellungsmodell der ASPState-Datenbank auf einfach (standardmäßig auf vollständig).

(b) ändern Sie sich ASPState_Job_DeleteExpiredSessions, um alle 5 oder 10 Minuten anstatt jede Minute zu laufen. Wenn die Ausführung dieses Jobs> 1 Minute dauert, wird er immer ausgeführt. Hoffentlich ist es nicht vollständig linear, was bedeutet, dass das Warten von 5 Minuten anstelle von 1 nicht mehr als 5 Minuten Arbeit anstelle von 1 in die Warteschlange stellt. Die Umsetzung meiner obigen Vorschläge sollte dabei helfen.

Aaron Bertrand
quelle