【发布时间】:2018-11-22 08:09:20
【问题描述】:
我需要使用锁来执行一些 SQL Server 事务(选择 + 插入)以防止冲突。我有以下场景:我有一个主键是整数但不是自动递增的表(旧版,不要问),因此它的值确定如下:
- 选择从表中检索最大 ID 值
- ID 加一
- 使用新 ID 在表中插入一条新记录
这一切都在一个事务中完成,SQL命令如下:
SELECT @maxvalue = max(MyId) FROM MyTable
IF @maxvalue > 0
SET @maxvalue = @maxvalue + 1
ELSE
SET @maxvalue = 1
INSERT INTO MyTable(MyValue, ...) VALUES(@maxvalue, ...)
在某些情况下,这很容易出现重复 ID,编写它的人将其放入循环中,并在发生重复键错误时重试该操作。所以我改变了这一点,删除循环并在事务级别设置锁,如下所示:
SELECT @maxvalue = max(MyId) FROM MyTable WITH (HOLDLOCK, TABLOCKX)
IF @maxvalue > 0
SET @maxvalue = @maxvalue + 1
ELSE
SET @maxvalue = 1
INSERT INTO MyTable(MyValue, ...) VALUES(@maxvalue, ...)
所以我指定了两个table hints、HOLDLOCK 和TABLOCKX。这对于某些数据库来说看起来不错,但对于一些在该表中有数万条记录的数据库来说,这个事务需要很长时间,大约 10 分钟。在 SQL Server 活动监视器中查看我可以看到事务已暂停,尽管在很长一段时间后它已成功执行。
然后,我将提示更改为 (HOLDLOCK, TABLOCK),并且工作速度与使用提示之前一样快。
问题是我不确定这是我正在寻找的最佳组合还是其他更合适的组合。我见过Confused about UPDLOCK, HOLDLOCK 和https://www.sqlteam.com/articles/introduction-to-locking-in-sql-server,但希望得到专家的意见。
【问题讨论】:
标签: sql sql-server transactions locking