Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 无休止的争论:SQL Server中的原子插入、锁定和事务。到此为止_Sql Server_Sql Server 2008_Concurrency_Locking - Fatal编程技术网

Sql server 无休止的争论:SQL Server中的原子插入、锁定和事务。到此为止

Sql server 无休止的争论:SQL Server中的原子插入、锁定和事务。到此为止,sql-server,sql-server-2008,concurrency,locking,Sql Server,Sql Server 2008,Concurrency,Locking,编辑:我的问题是,为什么我的第一个代码示例有效?请继续读 Edit1:毫无疑问,唯一约束是确保不发生重复的正确方法。这是必然的。然而,有时我们需要知道我们正在尝试一个重复的条目。此外,这篇文章不仅仅是处理副本 这可能会重复大约100多个问题。我读过无数关于原子更新、锁和并发性等简单问题的困惑和矛盾 我发现博客和专家在这些问题上存在广泛的分歧。在这里,我根据人们建议的各种解决方案提供测试代码,指出结果,陈述我的观点,并邀请您发表评论 上下文:我正在运行SQL Server 2008 Express

编辑:我的问题是,为什么我的第一个代码示例有效?请继续读

Edit1:毫无疑问,唯一约束是确保不发生重复的正确方法。这是必然的。然而,有时我们需要知道我们正在尝试一个重复的条目。此外,这篇文章不仅仅是处理副本

这可能会重复大约100多个问题。我读过无数关于原子更新、锁和并发性等简单问题的困惑和矛盾

我发现博客和专家在这些问题上存在广泛的分歧。在这里,我根据人们建议的各种解决方案提供测试代码,指出结果,陈述我的观点,并邀请您发表评论

上下文:我正在运行SQL Server 2008 Express SP2

我创建了以下测试表:

create table dbo.Temp (Col int)
该表故意没有任何约束,因为我们想要测试SQL代码思想,而不是约束

我在2个和3个查询窗口中同时运行了以下操作:

declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    update dbo.temp set Col = (SELECT Col from dbo.Temp) + 1
end
while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists
      (select 1 from dbo.temp where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (updlock) where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (XLOCK, ROWLOCK) where Col = @i)
end
可以看出,我没有使用任何显式锁定。所有数据库设置都是默认设置。我检查了Col的值,它是所需的数字:25000。没有遗漏什么

因为SQLServer是ACID,所以A告诉我们一条语句是以原子方式执行的。因此,基于上述内容,我们可以同意那些认为简单更新不需要锁的人的观点

接下来,我在3个查询窗口中同时运行了以下操作:

declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    update dbo.temp set Col = (SELECT Col from dbo.Temp) + 1
end
while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists
      (select 1 from dbo.temp where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (updlock) where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (XLOCK, ROWLOCK) where Col = @i)
end
结果是不正确的,尽管这是一种说法。缺少值、重复值和>5k行

接下来,我在3个查询窗口中同时运行了以下流行解决方案:

declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    update dbo.temp set Col = (SELECT Col from dbo.Temp) + 1
end
while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists
      (select 1 from dbo.temp where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (updlock) where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (XLOCK, ROWLOCK) where Col = @i)
end
结果不正确。缺少值、重复值和>5k行

接下来,对于那些怀疑SQL Server是否在事务中隐式包装了单个语句(也称为ACID)的人:

declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    begin tran
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (updlock) where Col = @i)
    commit tran
end
同样的错误结果

接下来,我在3个查询窗口中同时运行了以下操作:

declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    update dbo.temp set Col = (SELECT Col from dbo.Temp) + 1
end
while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists
      (select 1 from dbo.temp where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (updlock) where Col = @i)
end
declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    insert into dbo.temp select @i where not exists 
      (select 1 from dbo.temp with (XLOCK, ROWLOCK) where Col = @i)
end
这起作用了。仅限5k唯一值

接下来,在3个窗口中显示以下内容:

declare @i int
set @i = 0

while @i < 5000 begin
    set @i = @i + 1
    merge dbo.temp as t
    using (select @i) as test (Col)
    ON (t.Col = test.Col)
    when not matched then
        insert values (@i);
end
这起作用了。仅限5k唯一值

我的结论是:

SQL Server是单个SQL操作的原子,而不是作为一条语句出现的操作组。 正如许多人所示和建议的那样,UPDLOCK在提供在有争议的环境中保证更新完整性所需的锁定方面是无效的。 从锁定的角度来看,只有XLOCK可以保证多语句操作中的并发完整性和原子性,如图所示。 MERGE命令是单个命令,因此是原子的。 请自己测试一下


现在,有人能解释一下为什么我的第一个例子有效吗-

这里最好的解决方案是使用INT标识,让SQL Server处理INT列的唯一性。。。。。。。但这是众所周知的事实,这里没有什么新鲜事,真的……当然。我总是使用索引,并允许索引真正保证唯一性。然而,很明显,有时我们需要知道行的存在并相应地进行处理,在这种情况下,我们必须进行测试。你知道为什么例1有效吗?@Marc,作为旁注,我在另一篇帖子上与你进行了对话,但我们从未结束过。这是关于我写的一个CTE。你指出它是递归的,但我不明白为什么。既然你这么做了。知道你的事,我会注意的@Mrac感谢-已发送电子邮件:-奇怪的是,一个三次受欢迎的问题作为非问题关闭。