ASPState 数据库锁定和增长问题

ret*_*ala 8 sql-server locking session

我们使用 ASPState 数据库在 SQL Server 2005 群集上保留 .NET 会话状态。我们在高峰期看到一些奇怪的行为

  • DeleteExpiredSessions 过程通过代理作业每分钟运行一次。有时这项工作需要花费几分钟来运行和删除过期的会话

  • 从应用程序到 ASPState 数据库的请求非常缓慢。我相信这是因为 DeleteExpiredSessions 过程在表上持有排他锁

代码:

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                          
Run Code Online (Sandbox Code Playgroud)
  • 尽管数据库处于简单恢复状态,但日志文件正在填满,并且在某些情况下会强制自动增长

除了这些之外,跟踪显示对同一会话的多个请求快速连续出现。例如exec dbo.TempResetTimeout @id=N'32gghltsuoesnvlzbehchp2m2014c0f1'在 <1 秒内 14 次,所以我们想知道这是一个原因或拥塞,但不确定这种行为的根源。

对此行为的任何建议或解释将不胜感激。

Aar*_*and 5

我怀疑您将 Greg 的替换程序实施为先发制人的优化。一次一行的方法将锁定限制为单行,当然,但它会花费更长的时间 - 特别是如果您强制 SQL Server 以随机顺序攻击行。

我的建议是恢复到原来的程序:

ALTER PROCEDURE dbo.DeleteExpiredSessions
AS
BEGIN
  SET NOCOUNT ON;

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

  DELETE ASPState..ASPStateTempSessions 
    WHERE Expires < @now;
END
GO
Run Code Online (Sandbox Code Playgroud)

如果您发现这由于使用了锁而成为一个性能问题,您可以将其拆分,甚至使用以下方法减少对日志的影响:

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
Run Code Online (Sandbox Code Playgroud)

恕我直言,这比使用随机游标一次删除一行要好得多。您可以TOP (1000)根据实际观察调整该值。

其他一些可能有帮助的想法:

(a) 将 ASPState 数据库的恢复模型设置为简单(默认为完整)。

(b) 改为ASPState_Job_DeleteExpiredSessions每 5 或 10 分钟运行一次,而不是每分钟运行一次。如果此作业运行时间超过 1 分钟,则它将始终运行。希望它不是完全线性的,这意味着等待 5 分钟而不是 1 分钟不会排队超过 5 分钟而不是 1 分钟。实施我上面的建议应该对此有所帮助。