【问题标题】:Looking for the appropriate combination of table hints寻找合适的表格提示组合
【发布时间】: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 hintsHOLDLOCKTABLOCKX。这对于某些数据库来说看起来不错,但对于一些在该表中有数万条记录的数据库来说,这个事务需要很长时间,大约 10 分钟。在 SQL Server 活动监视器中查看我可以看到事务已暂停,尽管在很长一段时间后它已成功执行。

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

问题是我不确定这是我正在寻找的最佳组合还是其他更合适的组合。我见过Confused about UPDLOCK, HOLDLOCKhttps://www.sqlteam.com/articles/introduction-to-locking-in-sql-server,但希望得到专家的意见。

【问题讨论】:

    标签: sql sql-server transactions locking


    【解决方案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);   
    

    【讨论】:

    • 这是一个有趣的解决方案,但不幸的是,我无法使用它。我正在研究一个遗留系统。数据模型(表、列、索引等)以某种专有格式进行描述,并且数据库仅根据该描述进行相应更新。这不支持您的示例中的约束。添加这种支持对于这项特定任务来说太复杂了,不值得。
    • @MariusBancila 也许你可以使用第一部分?
    • 这将摆脱 if-else 部分,但它对竞争条件有何帮助?如果同时执行两次怎么办?它还不需要锁吗?
    • 更新表时,表被锁定。所以这将无法生成重复。
    猜你喜欢
    • 1970-01-01
    • 2019-09-29
    • 2016-12-13
    • 2010-09-11
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    相关资源
    最近更新 更多