今天修改一处并发问题,小记如下。
程序的核心代码包括以下存储过程(示例代码,未包含索引及TRY..CATCH逻辑)。
CREATE PROC GenerateLSH
@BizTypeID INT,
@Prefix VARCHAR(255),
@Result INT OUT
AS
BEGIN
DECLARE @ID INT
SELECT @ID = SegmentTable.SegmentTableID
FROM SegmentTable
WHERE (SegmentTable.BizTypeID = @BizTypeID) AND (SegmentTable.Prefix = @Prefix);
UPDATE SegmentTable SET
[MaxNo] = SegmentTable.MaxNo + 1
WHERE SegmentTable.SegmentTableID = @ID;
SELECT @Result = SegmentTable.MaxNo
FROM SegmentTable
WHERE SegmentTable.SegmentTableID = @ID;
END
GO;
程序的基本逻辑是这样的:
BEGIN TRAN
SQL_A;
Exec GenerateLSH @ID out;
SQL_B;
COMMIT TRAN;
程序在并发条件下经常出现超时情况,Profiler截取GenerateLSH执行时间没有发现明显规律。
转而一想,由于启用了RCSI,是否跟存储过程中唯一的一句Update语句有关。因为只有这一句会持有KEY锁。看SQL代码得知这个存储过程只能是线性执行,其持有的KEY锁生命周期为:
@time = TimePoint(Commit Tran) - TimePoint(Exec Proc)
以程序30秒的超时间隔计算,允许的并发数可粗略计算为:
@count = 30/@time
由于存储过程的线性执行方式不能修改,就只能修改@time的厚度,而Exec Proc和SQL_B之间没有先后顺序,因此拖后Exec Proc的时间点,使其无限靠近Commit是唯一解决办法。这样只是无限缩小@time,其最新值为:
@time = TimePoint(Last Stmt of Proc) - TimePoint(Update Stmt of Proc)
虽然该修改方式没有绝对消除并发问题,但是因为该语句的时间厚度在ms级别,使得我们的纯并发数能上升到1000以上,完全超出程序处理能力,可以认为问题解决。
修改程序代码,问题解决。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12700637/viewspace-1043764/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/12700637/viewspace-1043764/