MS SQL Server 中应用锁的限制

Bas*_*que 5 sql-server locking limits

Microsoft SQL Server 通过sp-getapplock命令和相关命令提供任意应用程序定义的锁定机制。

键, or resource_name,被指定为一个字符串,一个 varchar 255。但文档还提到键/名称是散列的。

所以这让我想知道:

  • 使用什么样的哈希函数?
  • 该散列函数的结果分布情况如何?
  • 我应该使用什么样的输入来扩大散列结果的分布,以尽量减少巧合碰撞的机会?
  • 我可以激活的应用锁数量的理论和实践限制是什么?
  • 应用锁使用哪些资源,例如内存量或内存限制?

我正在为特殊需求应用程序的许多表的行实施悲观锁定机制。作为我的应用锁键/名称,我计划使用一个代表每个表的数字与存储在每一行中的 ID 号相结合。示例键/名称可能类似于mydb_myschema_table0000000142_row0000241738. 我可能一次有许多活动,所以我需要了解这些限制。

Geo*_*son 8

我没有看到官方文档回答您的问题,但是您可以自己做一些事情(首先在测试/开发服务器上!)。这是我发现的:

除非您希望使用大量并发锁,否则您可能不会遇到任何问题。在 SQL Server 2017 CTP2.1 上,我能够获得1MM concurrent locks大约26 seconds. 没有碰撞,这似乎使用~286MB of memory.

SQL Server文档指定为32位,最多2,147,483,647锁“只受记忆”为64位(我假设你正在使用)。

测试脚本

下面是一个脚本,它获取 1MM 锁并对经过的时间、消耗的内存、遇到的冲突进行基本监控。

BEGIN TRAN;

DECLARE @result INT, 
    @i INT = 1,
    @locks_attempted INT = 1000000,
    @locks_acquired INT,
    @ts DATETIME2 = SYSDATETIME();

WHILE (@i <= @locks_attempted)
BEGIN
    DECLARE @Resource NVARCHAR(255) =
        'LongStringSoThatTheFirst32CharactersAreIdentical_' + CAST(@i AS VARCHAR)
    EXEC @result = sp_getapplock @Resource = @Resource, @LockMode = 'Exclusive';
    IF (@result <> 0) THROW 50000, 'Failed to acquire lock', 0
    SET @i = @i + 1;
END

DECLARE @elapsed_ms INT = DATEDIFF(MILLISECOND, @ts, SYSDATETIME());

SELECT @locks_acquired = COUNT(*)
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
    AND resource_type = 'APPLICATION';

-- Acquired 1000000 of 1000000 locks in 26351 milliseconds
RAISERROR('Acquired %i of %i locks in %i milliseconds', 0, 1,
    @locks_acquired, @locks_attempted, @elapsed_ms);

-- ~286MB of memory for OBJECTSTORE_LOCK_MANAGER
SELECT *
FROM sys.dm_os_memory_clerks
WHERE type = 'OBJECTSTORE_LOCK_MANAGER';

ROLLBACK;
Run Code Online (Sandbox Code Playgroud)

碰撞呢?

我在任何试验中都没有观察到冲突,但根据sys.dm_tran_locks的文档,似乎使用了 32 位哈希。使用如此短的哈希值,碰撞的几率应该相当高(见下图)。但是,即使使用10MM concurrent locks,我也没有实现碰撞。这可能表明哈希在底层更为复杂,并且 的resource_descriptionsys.dm_tran_locks仅显示哈希的前 32 位(类似于仅显示@Resource参数的前 32 个字符的方式)。或者它可能表明我很幸运。

如果您打算使用此策略,您应该检查您的实际数据是否有任何冲突。如果你这样做,你可以尝试把独特的元素(例如schema_idobject_id和你的ROWID)在的开始@Resource。(尚不完全清楚,但文档建议 的前 32 个字符@Resource可能与哈希组合以唯一标识锁。)

在此处输入图片说明

(图片来自Preshing on Programming

你为什么要这样做?

sp_getapplock对于与 SQL Server 自己提供的行级锁定类型类似的东西,大量使用它似乎是不寻常的。我假设您已经仔细考虑过其他方法,但如果您还没有这样做,您可能需要考虑不涉及 sp_getapplock 的其他解决方案。