Sql server 2008 MS SQL索引值更新

Sql server 2008 MS SQL索引值更新,sql-server-2008,tsql,indexing,sql-insert,Sql Server 2008,Tsql,Indexing,Sql Insert,设置: SQL Server 2008 R2 背景故事: 我们有一个一次在多个线程中调用的proc。这些线程化进程调用有时会将重叠的重复数据写入它们写入的表中。在insert语句中,我有一个NOT EXISTS子句来确保没有插入重复项,但我们仍然得到重复项 问题: NOT EXISTS子句做了一个简单的选择,是不是因为线程调用的插入间隔只有毫秒,所以NOT EXISTS子句使用的一些索引还没有更新?因此,在执行插入之前,它不会看到现有记录 想法: 这可能是因为我不理解SQL是如何工作的。如果我有

设置: SQL Server 2008 R2

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

问题: NOT EXISTS子句做了一个简单的选择,是不是因为线程调用的插入间隔只有毫秒,所以NOT EXISTS子句使用的一些索引还没有更新?因此,在执行插入之前,它不会看到现有记录

想法: 这可能是因为我不理解SQL是如何工作的。如果我有一个带有WHERE NOT EXISTS的insert,那么在执行insert之前是否会检查以确保没有任何记录存在?还是在插入每一行时以逐行方式进行检查?如果是前一个在执行任何插入之前检查所有,那么我认为其他调用之一可能尚未完成插入

我被难住了

下面是我正在做的一个例子:

INSERT INTO [SomeTable] (Col1,Col2) SELECT ColumnA, ColumnB FROM #TempTable WHERE NOT EXISTS ( SELECT 1 FROM [SomeTable] WHERE Col1 = #TempTable.ColumnA AND Col2 = #TempTable.ColumnB )
您需要在事务期间锁定表。其他线程将等待事务完成提交或回滚

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

BEGIN TRANSACTION

--do stuff

COMMIT TRANSACTION
默认情况下,SQL Server使用读提交隔离级别。这意味着在select过程中,仅当select正在主动访问该行时,才会保持每行上的读取锁定

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

即使是MERGE语句也不能阻止并发插入,因为搜索部分和插入部分之间有一段时间。有关更多详细信息,请参阅

对于包含支票和以下插入的整个事务,需要在不存在的行上保留一个锁。实现这一点的唯一方法是使用包装事务并将事务隔离级别设置为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分支

你能告诉我们密码吗?猜太长时间了。请参阅。您的代码中是否使用了事务?没有事务,并且进程长度为10000行:不过,这是一种直接的插入,它将记录从临时表插入到用户表中,而用户表中的条目并不存在。如果您为员工运行该过程,然后直接在之后再次运行,它不会插入任何内容,因为它会看到记录已经存在。添加了testCode示例。是的,在生产代码中就是这么简单。当OP检查是否存在时,他还需要能够锁定不存在的行。可重复读取不提供此功能。