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 次,所以我们想知道这是一个原因或拥塞,但不确定这种行为的根源。
对此行为的任何建议或解释将不胜感激。
我怀疑您将 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 分钟。实施我上面的建议应该对此有所帮助。
归档时间: |
|
查看次数: |
11455 次 |
最近记录: |