【问题标题】:sql locking for batch updates用于批量更新的 sql 锁定
【发布时间】:2012-12-06 10:37:30
【问题描述】:

我使用的是 SQL Server 2008 R2 和 C#。

我在 SQL Server 中插入一批行,其中列 Status 的值设置为 P。 之后,我检查有多少行已经有状态 R,如果少于 20 行,我将行更新为状态 R。 在插入和更新时,会一直添加和更新更多行。

我尝试了多种方式的事务和锁定,但仍然:在激活新批次的那一刻,有 20 多行状态为 R 几毫秒。在这几毫秒之后,它稳定回到 20。

有谁知道为什么突然锁定似乎不起作用? 示例代码、原因以及您可以在此主题上分享的任何内容都会很有用! 谢谢!

以下是我的存储过程:

      DECLARE @return BIT 
      SET @return = -1 
      DECLARE @previousValue INT 
      --insert the started orchestration 
      INSERT INTO torchestrationcontroller WITH (ROWLOCK)
                ([flowname],[orchestrationid],[status]) 
                VALUES      (@FlowName, @OrchestrationID, 'P') 

      --check settings 
      DECLARE @maxRunning INT 

      SELECT @maxRunning = maxinstances 
              FROM   torchestrationflows WITH (NOLOCK) 
              WHERE  [flowname] = @FlowName 

      --if running is 0, than you can pass, no limitation here                
       IF( @maxRunning = 0 ) 
        BEGIN 
            SET @return = 1 

            UPDATE torchestrationcontroller WITH(ROWLOCK) 
                    SET    [status] = 'R' 
                    WHERE  [orchestrationid] = @OrchestrationID 
        END 
      ELSE 
        --  BEGIN 


RETRY: -- Label RETRY
BEGIN TRY
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION T1

        --else: check how many orchestrations are now running 
        --start lock table 
        DECLARE @currentRunning INT 

      SELECT @currentRunning = Count(*) 
              FROM   torchestrationcontroller WITH (TABLOCKX) --Use an exclusive lock that will be held until the end of the transaction on all data processed by the statement
              WHERE  [flowname] = @FlowName 
              AND [status] = 'R'                  
              --CASE

      IF( @currentRunning < @maxRunning ) 
        BEGIN 
            -- less orchestrations are running than allowed 
            SET @return = 1 

            UPDATE torchestrationcontroller WITH(TABLOCKX) 
            SET    [status] = 'R' 
            WHERE  [orchestrationid] = @OrchestrationID 
        END 
      ELSE 
        -- more or equal orchestrations are running than allowed 
        SET @return = 0 

      --end lock table 
      SELECT @Return 

COMMIT TRANSACTION T1
END TRY
BEGIN CATCH
--PRINT 'Rollback Transaction'
ROLLBACK TRANSACTION
IF ERROR_NUMBER() = 1205 -- Deadlock Error Number
BEGIN

    WAITFOR DELAY '00:00:00.05' -- Wait for 5 ms
    GOTO RETRY -- Go to Label RETRY
END
END CATCH

【问题讨论】:

  • 显然如果两个线程同时读取计数,然后继续更新,行数可能会超过 20。一些示例代码将有助于诊断确切情况。
  • 我已经添加了我的代码,希望你能在这方面提供更多帮助。我以为问题就像你说的那样,但是有没有办法解决这个问题?我认为隔离级别可能对此有所帮助。
  • maxRunning = 0 的免费通行证看起来很可疑...... 50 个线程可能会读取它,然后更新 50 行

标签: sql transactions locking sql-server-2008-r2


【解决方案1】:

我已经能够通过在树存储过程上设置隔离级别可序列化+事务来修复它(其中两个我没有提到,因为我认为它们对这个问题并不重要)。显然是多个存储过程的组合相互干扰。

如果您知道更好的修复方法,可以给我带来更好的性能,请告诉我!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    相关资源
    最近更新 更多