寻找适当的表格提示组合

时间:2018-11-22 08:09:20

标签: sql sql-server transactions locking

我需要使用锁来执行一些SQL Server事务(选择+插入),以防止发生冲突。我有以下情形:我有一个表,它的主键是一个整数,但不会自动递增(传统,不要问),因此其值确定如下:

  • select从表中检索最大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,并且编写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 hintsHOLDLOCKTABLOCKX。对于某些数据库来说,这看起来不错,但对于该表中具有成千上万条记录的数据库而言,此事务花费了很多时间,大约10分钟。在SQL Server活动监视器中查看,尽管成功执行了很长时间,但我可以看到事务已暂停。

然后,我将提示更改为(HOLDLOCK, TABLOCK),并且工作速度与使用提示之前一样快。

问题是我不确定这是否是我要寻找的最佳组合,还是其他更合适的组合?我见过Confused about UPDLOCK, HOLDLOCKhttps://www.sqlteam.com/articles/introduction-to-locking-in-sql-server,但不胜感激专家的意见。

1 个答案:

答案 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);