无鱼之水

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

    今天修改一处并发问题,小记如下。
    程序的核心代码包括以下存储过程(示例代码,未包含索引及TRY..CATCH逻辑)。

 

持锁存储过程
1 CREATE PROC GenerateLSH
2 @BizTypeID INT,
3 @Prefix VARCHAR(255),
4 @Result INT OUT
5  AS
6 BEGIN
7 DECLARE @ID INT
8 SELECT @ID = SegmentTable.SegmentTableID
9 FROM SegmentTable
10 WHERE (SegmentTable.BizTypeID = @BizTypeID) AND (SegmentTable.Prefix = @Prefix);
11 UPDATE SegmentTable SET
12 [MaxNo] = SegmentTable.MaxNo + 1
13 WHERE SegmentTable.SegmentTableID = @ID;
14 SELECT @Result = SegmentTable.MaxNo
15 FROM SegmentTable
16 WHERE SegmentTable.SegmentTableID = @ID;
17 END
18 GO;

  程序的基本逻辑是这样的:
  

1 BEGIN TRAN
2 SQL_A;
3 Exec GenerateLSH @ID out;
4 SQL_B;
5 COMMIT TRAN;

    程序在并发条件下经常出现超时情况,Profiler截取GenerateLSH执行时间没有发现明显规律。
    转而一想,由于启用了RCSI,是否跟存储过程中唯一的一句Update语句有关。因为只有这一句会持有KEY锁。这个存储过程只能是线性执行,其持有的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以上,完全超出程序处理能力,可以认为问题解决。
    修改程序代码,问题解决。 

posted on 2010-12-29 18:36  陈伟强  阅读(326)  评论(2编辑  收藏  举报