【问题标题】:MS SQL Index value updatesMS SQL 索引值更新
【发布时间】:2013-06-06 15:44:06
【问题描述】:

设置: SQL Server 2008 R2

背景故事: 我们有一个同时在多个线程中调用的 proc。这些线程化的 proc 调用有时会将重叠(重复)数据写入它们写入的表中。在插入语句中,我有一个“NOT EXISTS”子句来确保不插入重复项,但我们仍然得到重复项。

问题: “NOT EXISTS”子句做了一个简单的选择,因为线程调用的插入仅相隔几毫秒,一些索引(特别是“NOT EXISTS”子句使用的索引)是否可能尚未更新?因此在插入之前看不到现有记录?

想法: 这可能是我不理解 SQL 是如何做它的事情的。如果我有一个带有“WHERE NOT EXISTS”的插入,它是否会在插入之前检查以确保不存在任何记录?还是在插入每一行时以逐行方式检查?如果是前者(在进行任何插入之前检查所有内容),那么我认为其他调用之一可能尚未完成它的插入。

我被难住了。

这是我正在做的一个例子:

插入 [SomeTable] (Col1,Col2)
选择
    A列,
    B栏
从
    #TempTable
在哪里
    不存在 (
        选择 1
        来自 [SomeTable]
        其中 Col1 = #TempTable.ColumnA
              AND Col2 = #TempTable.ColumnB
    )

【问题讨论】:

  • 你能给我们看看代码吗?猜测时间太长了。见Writing The Perfect Question
  • 您是否在代码中使用事务?
  • 无事务,proc 有 10,000 行长。 :) 这是一个直接的插入,它将临时表中的记录插入到用户表中,其中该条目不存在。如果您为员工运行 proc,然后直接再次运行,它不会插入任何内容,因为它看到记录已经存在。test
  • 添加了代码示例。是的,在生产代码中就是这么简单。

标签: sql-server-2008 tsql indexing sql-insert


【解决方案1】:

您需要在事务期间锁定表。其他线程将等待事务完成(提交或回滚)。

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

BEGIN TRANSACTION

--do stuff

COMMIT TRANSACTION

http://msdn.microsoft.com/en-us/library/ms173763.aspx

【讨论】:

  • 当 OP 检查存在时,他还需要能够锁定不存在的行。 REPEATABLE READ 不提供。
【解决方案2】:

SQL Server 默认使用READ COMMITTED 隔离级别。这意味着在选择期间,每行上的读锁仅在选择主动访问该行时才被持有。

这意味着在 SELECT 完成之后和 INSERT 发生之前,另一个线程可以插入该行,即使该间隙只有几纳秒长。

即使是MERGE 语句也不会阻止并发插入,因为搜索部分和插入部分之间存在一些时间。 (详情请参阅http://sqlity.net/en/1645/merge-wonders-insert-or-use/。)

您需要为整个事务(包括检查和以下插入)在不存在的行上持有一个锁。实现这一点的唯一方法是使用包装事务并将事务隔离级别设置为SERIALIZABLE

类似:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRAN
  IF(NOT EXISTS(SELECT ...))
  BEGIN
   INSERT....
  END;
COMMIT;

更新:

因为您现在提供了一个示例,试图同时执行这两个步骤,所以让我从引用的文章中重新发布我的示例,其中删除了对这种情况不重要的所有内容:

MERGE dbo.Product WITH(HOLDLOCK) AS p
USING (VALUES(@ProductName, @ProductNumber))n(Name,ProductNumber)
ON p.ProductNumber = n.ProductNumber
WHEN NOT MATCHED THEN
INSERT(Name, ProductNumber)
VALUES(n.Name, n.ProductNumber)

HOLDLOCK 提示(在本地)与将事务隔离级别设置为SERIALIZABLE 具有相同的效果。因为MERGE 是一个数据更改语句,它会在事务中自动执行。

使用MERGE 语句的另一个优点是,如果以后需要,您可以轻松添加UPDATE 分支。

【讨论】:

    猜你喜欢
    • 2017-11-15
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 2019-01-01
    相关资源
    最近更新 更多