我需要使用锁来执行一些SQL Server事务(选择+插入),以防止发生冲突。我有以下情形:我有一个表,它的主键是一个整数,但不会自动递增(传统,不要问),因此其值确定如下:
所有这些操作都是在事务中完成的,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,并且编写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,但不胜感激专家的意见。
答案 0 :(得分:1)
这应该防止重复。添加了额外的一列来说明如何使用更多列:
DECLARE @val INT
INSERT MyTable(MyValue, val2)
SELECT coalesce(max(MyValue),0) + 1, @val
FROM mytable
为了确保也要创建唯一的约束:
ALTER TABLE MyTable
ADD CONSTRAINT UC_MyValue UNIQUE (MyValue);