我在SQL服务器数据库上有一个长时间运行的存储过程。我不希望它每十分钟运行一次以上。
存储过程运行后,我希望将最新结果存储在LatestResult
表中,与时间一致,并且对该过程的所有调用都会在接下来的十分钟内返回该结果。
这一点相对简单,但是我们发现,因为该过程检查LatestResult
表并更新它,当两个用户调用该过程时,大型用户基站会出现许多死锁。同时。
在客户端/线程情况下,我会通过使用锁来解决这个问题,让第一个用户锁定函数,第二个用户遇到锁,等待结果,第一个用户完成程序调用,更新LatestResult
表,然后解锁第二个用户,然后第二个用户从LatestResult
表中获取结果。
有没有办法在SQL Server中实现这种锁定?
修改
这基本上是代码看起来没有错误检查调用的方式:
DECLARE @LastChecked AS DATETIME
DECLARE @LastResult AS NUMERIC(18,2)
SELECT TOP 1 @LastChecked = LastRunTime, @LastResult = LastResult FROM LastResult
DECLARE @ReturnValue AS NUMERIC(18,2)
IF DATEDIFF(n, @LastChecked, GetDate()) >= 10 OR NOT @LastResult = 0
BEGIN
SELECT @ReturnValue = ABS(ISNULL(SUM(ISNULL(Amount,0)),0)) FROM Transactions WHERE ISNULL(DeletedFlag,0) = 0 GROUP BY GroupID ORDER BY ABS(ISNULL(SUM(ISNULL(Amount,0)),0))
UPDATE LastResult SET LastRunTime = GETDATE(), LastResult = @ReturnValue
SELECT @ReturnValue
END
ELSE
BEGIN
SELECT @LastResult
END
我不确定分组是怎么回事,但是我发现了一个测试系统,执行时间大约是4秒。
我认为有一些工作计划存档其中一些记录并将其归结为运行总计,这可能有助于确定这四秒钟表中有数百万行......
答案 0 :(得分:4)
这是使用应用程序锁定的有效机会(请参阅sp_getapplock和sp_releaseapplock),因为它是对您定义的概念进行锁定,而不是对任何给定表中的任何特定行进行锁定。这个想法是你创建一个事务,然后创建这个具有一个untifier的任意锁,其他进程将等待输入那段代码,直到锁被释放。这与app层的lock()
类似。 @Resource
参数是任意"概念"的标签。在更复杂的情况下,您甚至可以在其中连接CustomerID或其他内容,以实现更精细的锁定控制。
DECLARE @LastChecked DATETIME,
@LastResult NUMERIC(18,2);
DECLARE @ReturnValue NUMERIC(18,2);
BEGIN TRANSACTION;
EXEC sp_getapplock @Resource = 'check_timing', @LockMode = 'Exclusive';
SELECT TOP 1 -- not sure if this helps the optimizer on a 1 row table, but seems ok
@LastChecked = LastRunTime,
@LastResult = LastResult
FROM LastResult;
IF (DATEDIFF(MINUTE, @LastChecked, GETDATE()) >= 10 OR @LastResult <> 0)
BEGIN
SELECT @ReturnValue = ABS(ISNULL(SUM(ISNULL(Amount, 0)), 0))
FROM Transactions
WHERE DeletedFlag = 0
OR DeletedFlag IS NULL;
UPDATE LastResult
SET LastRunTime = GETDATE(),
LastResult = @ReturnValue;
END;
ELSE
BEGIN
SET @ReturnValue = @LastResult; -- This is always 0 here
END;
SELECT @ReturnValue AS [ReturnValue];
EXEC sp_releaseapplock @Resource = 'check_timing';
COMMIT TRANSACTION;
你需要自己管理错误/ ROLLBACK(如链接的MSDN文档中所述),所以放入通常的TRY / CATCH。但是,这确实可以让您管理情况。
如果对这个过程存在任何争议,那么在锁定资源之后立即执行查找就不应该是单行表中的SELECT,然后是(理想情况下)只是一个IF语句如果10分钟计时器没有经过,则返回最后的已知值。因此,大多数电话应该很快处理。
请注意: sp_getapplock
/ sp_releaseapplock
应谨慎使用;应用程序锁定绝对非常方便(例如在这种情况下),但它们只应在绝对必要时使用。