【问题标题】:Best practice: SQL SP serialized execution最佳实践:SQL SP 序列化执行
【发布时间】:2018-04-20 12:32:25
【问题描述】:

我们有一个 SP,它在插入行之后执行。它会更新事务中的多个表,但在某些情况下,当插入几行并同时执行 SP 时 - 它会陷入死锁。我们尝试对其进行优化,并降低了以死锁结束的机会 - 但无法避免。

现在我们尝试了另一种方式(这个 SP 在事务中运行):

DECLARE @padLock         INT

BEGIN TRY

EXEC @padLock = sp_getapplock @Resource='mytable_modify', @LockMode='Exclusive', @LockOwner='Transaction';

IF @padLock < 0 
   THROW 99888, 'Lock named [mytable_modify] cannot be acquired.', 1

...
do some stuff which might cause deadlock
...
EXEC sp_releaseapplock @Resource = 'mytable_modify', @LockOwner='Transaction';

END TRY
BEGIN CATCH
   SELECT 
       @strErrMsg = ERROR_MESSAGE() + 
                       'Line:' + CONVERT(varchar(5), ERROR_LINE()),
       @intErrSeverity = ERROR_SEVERITY(),
       @intErrState = ERROR_STATE();

  if @padLock >= 0  
    EXEC sp_releaseapplock @Resource = 'mytable_modify', @LockOwner='Transaction';

    RAISERROR(@strErrMsg,   -- Message text.
                @intErrSeverity,  -- Severity.
                @intErrState      -- State
                );
END CATCH;

这是一种好的做法,还是我们仍然有麻烦?

【问题讨论】:

    标签: sql sql-server-2012 locking deadlock


    【解决方案1】:

    获取粗粒度锁(此处使用sp_getapplock)将避免死锁,但会牺牲并发性和吞吐量。

    我不会把它称为一个好的做法,但我发现sp_getapplock 在无法轻松避免死锁并且由此产生的单线程性能对您来说是可以接受的特殊情况下是一种可接受的解决方案工作量。如果“做一些事情”需要几毫秒,那么除非您需要维持每秒数百个的速率,否则可能没有性能问题。

    【讨论】:

    • 我也不会说它是一种“实践”,我们将死锁情况替换为超时情况。主要区别在于 sp_getapplock 有一个超时参数,所以在不改变调用方的情况下,我们可以在 DB 端等待一段时间。
    • 长时间运行的事务尤其成问题,因为序列化访问会更明显地降低吞吐量,并且在您的情况下,会导致超时。也许更多的查询/索引调整可以缓解这种情况。
    猜你喜欢
    • 2013-07-27
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    相关资源
    最近更新 更多